安卓input子系统是经过事件管道 到达系统的各个层。html
在最低层,物理输入设备产生了描述的状态变化的 信号,如按键 和 触摸接触点。而后进行编码,并以某种方式发送这些信号,例如经过USB HID报告或I2C总线。这些信号被linux Kernel的驱动 解码。驱动会把这些信号翻译成 标准的事件类型 和 代码。Linux内核 在linux/input.h 中定义了一套标准的事件类型和代码。java
android的 EventHub 组件 经过打开dev/input 中的设备文件的方式从linux kernel读取这些输入事件,而后android的 InputReader 组件 会把这些linux输入事件翻译成一个android输入事件流.。
linux
在翻译过程当中涉及到device configuration, keyboard layout files, and various mapping tables.三个配置文件。最后InputReader 会把这些翻译好的事件发送给合适的应用程序窗口。
总的来看android4.0的input子系统能够分为两部分,安卓部分和linuxkernel部分。android
这个文档咱们只分析Android部分,Kernel会在另外一篇文章里说明。c++
Android开机时候会建立一个进程来启动各类服务,其中有一个会启动input的服务,这是android input的运行时候的核心,下面咱们具体来看。
1、InputDispatcher 和 InputReader线程 的建立过程
这两个线程是Input服务的核心线程,当android开机之后会首先创建这两个线程,而后进一步的完成整个input模块的初始化。InputReader负责input事件的读取,InputDispatcherThread负责将input事件的分发给上层app。
算法
下面咱们从看这两个线程的建立过程, android开机过程 中咱们知道开机后系统会建立ServerThread这个线程来启动不少服务, 这两个线程也是从这里启动的,Android开始启动服务函数在
数组
\android\frameworks\base\services\java\com\android\server\SystemServer.java中缓存
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
private static final String ENCRYPTED_STATE = "1";
ContentResolver mContentResolver;
void reportWtf(String msg, Throwable e) {
Slog.w(TAG, "***********************************************");
Log.wtf(TAG, "BOOT FAILURE " + msg, e);
}
@Override
public void run() {
。。。。。。
。。。。。。
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ActivityManagerService.self().setWindowManager(wm);
。。。。。
。。。。。。
}
这里执行WindowManagerService.main()函数建立Window Manager的服务咱们来看WindowManagerService.main()
具体代码在\android\frameworks\base\services\java\com\android\server\wm\WindowManagerService.java :
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) {
WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs);
thr.start();
synchronized (thr) {
while (thr.mService == null) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
return thr.mService;
}
}
函数里调用new WMThread(context, pm, haveInputMethods, allowBootMsgs);
咱们看WMThread定义在\android\frameworks\base\services\java\com\android\server\wm\WindowManagerService.java
static class WMThread extends Thread {
WindowManagerService mService;
private final Context mContext;
private final PowerManagerService mPM;
private final boolean mHaveInputMethods;
private final boolean mAllowBootMessages;
public WMThread(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean allowBootMsgs) {
。。。。。。。。
。。。。。。。。
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods, mAllowBootMessages);
。。。。
。。。。。。
}
这个函数调用了new WindowManagerService(mContext, mPM, mHaveInputMethods, mAllowBootMessages)
咱们继续看这个函数 也在这个文件中代码以下:
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean showBootMsgs) {
。。。。。。。。。。。
。。。。。。。。。。。
mInputManager = new InputManager(context, this);
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
thr.start();
synchronized (thr) {
while (!thr.mRunning) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
}
mInputManager.start();
}
能够看到这里调用mInputManager = new InputManager(context, this);来建立了Java层的input管理器,
下面继续看InputManager()在\android\frameworks\base\services\java\com\android\server\wm\InputManager.java中
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
this.mCallbacks = new Callbacks();
Looper looper = windowManagerService.mH.getLooper();
Slog.i(TAG, "Initializing input manager");
nativeInit(mContext, mCallbacks, looper.getQueue());
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
注意看这里的nativeInit(mContext, mCallbacks, looper.getQueue());这句,
这个函数定义private static native void nativeInit(Context context, Callbacks callbacks,
MessageQueue messageQueue);
说明这个函数是native层的一个函数,咱们继续来翻这个函数的定义,在android\frameworks\base\services\jni
\com_android_server_InputManager.cpp中这是一个c++函数,看来是调用一个动态连接库。具体代码:
static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
。。。。。。。。。
}//定义一个 JNINativeMethod而后在下面函数中注册
int register_android_server_InputManager(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "com/android/server/wm/InputManager",
gInputManagerMethods, NELEM(gInputManagerMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
Android的native层与java层都是这么调用的。咱们继续看看
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
if (gNativeInputManager == NULL) {
sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
} else {
LOGE("Input manager already initialized.");
jniThrowRuntimeException(env, "Input manager already initialized.");
}
}
这里调用了gNativeInputManager = new NativeInputManager(contextObj, callbacksObj,looper);继续看这个函
数 也在当前文件下:
NativeInputManager::NativeInputManager(jobject contextObj,
jobject callbacksObj, const sp<Looper>& looper) :
mLooper(looper) {
。。。。。。。。。
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}数据结构
这里sp<EventHub> eventHub = new EventHub();EventHub是与kernel打交道的管理器 它处理了全部kernel传上来
的input事件并转换处理发送给framework层使用。还有mInputManager = new InputManager(eventHub,this,this);
InputManager负责一些input的系统的初始化和正常工做时候一些管理工做。app
看完代码发现eventHub的运行是由InputManager调用的,所以咱们先从InputManager看起:
先看InputManager在\android40\frameworks\base\services\input\ InputManager.cpp
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
注意这两个函数的参数,参数mReade定义sp<InputReaderInterface> mReader;这是定义类指针的一种方式,知道这
两个是类的指针就能够了。他们的赋值在\android\frameworks\base\services\input\InputManager.cpp
namespace android {
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
这里InputReaderThread 和InputDispatcherThread 两个线程就建立完成了,咱们还须要对他们实现代码进行一小
下分析InputReader和InputDispatcher定义代码分别在\android\frameworks\base\services\input\InputReader.cpp
\android\frameworks\base\services\input\InputDispatcher.cpp 中
他们的代码为
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
定义居然是空的,仅仅是传进去一个类的指针而已。那么这两个线程运行什么呢?这个问题我百度了不少资料终于
找到了。\android\frameworks\base\services\java\com\android\server\wm\WindowManagerService.java中
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean showBootMsgs) {
。。。。。。。。。。。
。。。。。。。。。。。
mInputManager = new InputManager(context, this);
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
thr.start();
synchronized (thr) {
while (!thr.mRunning) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
}
mInputManager.start();
}
这里调用了mInputManager.start();而后
\android\frameworks\base\services\java\com\android\server\wm\InputManager.java
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart();
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
调用了nativeStart();而后
android\frameworks\base\services\jni\ com_android_server_InputManager.cpp
static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
{ "nativeStart", "()V",
(void*) android_server_InputManager_nativeStart },
。。。。。。。。。。。。。。。。。。。。。
而后本文件下
static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
if (checkInputManagerUnitialized(env)) {
return;
}
status_t result = gNativeInputManager->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
这里调用status_t result = gNativeInputManager->getInputManager()->start();而后
\android\frameworks\base\services\input\InputManager.cpp
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
终于找到了status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
而后仔细看这两个类并无实现这个函数,所以他们会调用他们的父类public Thread里的 Run 方法咱们来看这个
代码\android40\frameworks\base\libs\utils\ Threads.cpp
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear(); // "this" may have gone away after this.
return UNKNOWN_ERROR;
}
// Do not refer to mStatus here: The thread is already running (may, in fact
// already have exited with a valid mStatus result). The NO_ERROR indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return NO_ERROR;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
顺着函数一路跟踪下去会发现这个函数最终会无限执行Thread:: threadLoop()这个函数,这里就很少作说明了。
把代码位置贴出来 \android40\frameworks\base\libs\utils\ Threads.cpp的int Thread::_threadLoop(void*user)
函数。就在刚才的两个文件中咱们下一步找到线程的: threadLoop()
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
到了这里这两个线程终于建立完成了,下面就能够开始事件的读取和处理了,咱们从读取事件来说,先读取事件才
能分发处理事件
2、 Input事件的读取
\android\frameworks\base\services\input\InputReader.cpp
void InputReader::loopOnce() {
。。。。。。。。。。。
。。。。。。
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
。。。。。。。。。
。。。。。。。。。。。
}
这里涉及到了刚才建立的EventHub,EventHub是与内核 打交道的模块,当碰到写的驱动很差用时,可能须要动这个
模块,所以重点来看这个模块代码,咱们从getEvents这个函数看起在
\android40\frameworks\base\services\input\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize){
LOG_ASSERT(bufferSize >= 1); //buffsize必须>=1
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize]; //定义数据缓存 注解1
RawEvent* event = buffer; //保存缓存基地址
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); //获取系统当前时间
//若是须要就从新打开设备
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
LOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked(); //关闭全部设备
mNeedToScanDevices = true; //下次运行须要从新扫描全部设备
break; // return to the caller before we actually rescan
}
//报告最近的被添加删除的设备
// Report any devices that had last been added/removed.
while (mClosingDevices) { //若是队列有数据
Device* device = mClosingDevices;
LOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_REMOVED; //报告类型DEVICE_REMOVED
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break; //凑够bufferSize个就退出
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked(); //打开全部设备 注解2
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != NULL) { //报告被添加的最新设备
Device* device = mOpeningDevices;
LOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
if (mNeedToSendFinishedDeviceScan) { //若是设备扫描并报告完成
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN; //发送一个FINISHED_DEVICE_SCAN事件
event += 1;
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//从mPendingEventItems中读取事件
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {//断定事件类型EPOLL_ID_INOTIFY /dev/input下
//文件有变化时才会发送这个事件 注解3
if (eventItem.events & EPOLLIN) {
mPendingINotify = true; //有了设备变化
} else {
LOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) { //看事件类型是否为EPOLL_ID_WAKE 注解4
if (eventItem.events & EPOLLIN) {
LOGV("awoken after wake()");
awoken = true; //唤醒整个input系统
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));//把管道里的数据读出来
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
LOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
//若是不是EPOLL_ID_INOTIFY和EPOLL_ID_WAKE 那么获得发送事件的设备的索引
if (deviceIndex < 0) {
LOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
eventItem.events, eventItem.data.u32);
continue;
}
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer, //读取这个设备的event数据
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { //看是否是读取成功了
// Device was removed before INotify noticed.
LOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d capacity: %d errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
LOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
//计算此次读取的input_event的个数
for (size_t i = 0; i < count; i++) {
const struct input_event& iev = readBuffer[i];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
#ifdef HAVE_POSIX_CLOCKS
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
// event dispatch latency from the time the event is enqueued onto
// the evdev client buffer.
//
// The event's timestamp fortuitously uses the same monotonic clock
// time base as the rest of Android. The kernel event device driver
// (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
// The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
// calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
// system call that also queries ktime_get_ts().
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
+ nsecs_t(iev.time.tv_usec) * 1000LL;
LOGV("event time %lld, now %lld", event->when, now);
#else
event->when = now;
#endif
event->deviceId = deviceId; //将input_event转换成android的RawEvent类型
event->type = iev.type;
event->scanCode = iev.code;
event->value = iev.value;
event->keyCode = AKEYCODE_UNKNOWN;
event->flags = 0;
if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
&event->keyCode, &event->flags);
LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
iev.code, event->keyCode, event->flags, err);
}
event += 1;
}
capacity -= count;
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1; //凑够256就退出
break;
}
}
} else {
LOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.string());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {//若是有/dev/input下的设
//备有变化 而且还读取到了设备变化的事件
mPendingINotify = false;
readNotifyLocked(); //那么就打开这个设备 这个函数代码都在本目录下
//很简单能看懂 这里就不作说明了
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) { //若是有设备变化了 就跳过此次循环
continue;
}
//咱们读取到了 事件,或者 须要唤醒input模块 那么就当即报告全部事件给android上层
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during epoll_wait(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
// a kernel wake lock. However, once the last pending event has been read, the device
// driver will release the kernel wake lock. To prevent the system from going to sleep
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//读取mEpollFd的事件到mPendingEventItems 注解3 注解4
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
// On an SMP system, it is possible for the framework to read input events
// faster than the kernel input device driver can produce a complete packet.
// Because poll() wakes up as soon as the first input event becomes available,
// the framework will often end up reading one event at a time until the
// packet is complete. Instead of one call to read() returning 71 events,
// it could take 71 calls to read() each returning 1 event.
//
// Sleep for a short period of time after waking up from the poll() to give
// the kernel time to finish writing the entire packet of input events.
if (mNumCpus > 1) {
usleep(250);
}
}
}
// All done, return the number of events we read.
return event - buffer; //返回读取到事件个数
//到这里就把所读取到的事件送给InputReader::loopOnce()来处理了
}
注解1:
input_event 的定义,这个就是linux的input_event 的定义
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
注解2:
打开全部文件的方法
static const char *DEVICE_PATH = "/dev/input"; //定义input设备的目录
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH); //扫描这个目录
if(res < 0) {
LOGE("scan dir failed for %s\n", DEVICE_PATH);
}
}
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname); //打开这个目录 这个函数实如今\android40\bionic\libc\unistd\opendir.c
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) { //打开其中的一个文件
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
openDeviceLocked(devname);//这个函数很重要 看下面
}
closedir(dir);
return 0;
}
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
LOGV("Opening device: %s", devicePath);
int fd = open(devicePath, O_RDWR);打开这个目录
if(fd < 0) {
LOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
InputDeviceIdentifier identifier;
// Get device name.名称
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
// Check to see if the device is on our excluded list 检查这个设备是否在咱们的链表上
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const String8& item = mExcludedDevices.itemAt(i);
if (identifier.name == item) {
LOGI("ignoring event id %s driver %s\n", devicePath, item.string());
close(fd);
return -1;
}
}
// Get device driver version. 驱动版本
int driverVersion;
if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
// Get device identifier. 设备ID
struct input_id inputId;
if(ioctl(fd, EVIOCGID, &inputId)) {
LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
// Get device physical location.//物理地址
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location.setTo(buffer);
}
// Get device unique id.
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId.setTo(buffer);
}
// Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
LOGE("Error %d making device file descriptor non-blocking.", errno);
close(fd);
return -1;
}
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
#if 0
LOGI("add device %d: %s\n", deviceId, devicePath);
LOGI(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
LOGI(" name: \"%s\"\n", identifier.name.string());
LOGI(" location: \"%s\"\n", identifier.location.string());
LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
LOGI(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
#endif
// Load the configuration file for the device.加载设备的配置文件
loadConfigurationLocked(device);
// Figure out the kinds of events the device reports.读取设备 数据的类型
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
//这个设备若是是键盘 那么是否含有 游戏手柄的特殊键 有的话作特殊处理
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
sizeof_bit_array(KEY_MAX + 1));
bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
sizeof_bit_array(BTN_MOUSE))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this is a cursor device such as a trackball or mouse. 莫非是鼠标?
if (test_bit(BTN_MOUSE, device->keyBitmask)
&& test_bit(REL_X, device->relBitmask)
&& test_bit(REL_Y, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}
// See if this is a touch pad.仍是触摸板
// Is this a new modern multi-touch driver?居然多点触控?
if (test_bit(ABS_MT_POSITION_X, device->absBitmask) //靠x y坐标来断定
&& test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
// Some joysticks such as the PS3 controller report axes that conflict//因此不许还要加点别的
// with the ABS_MT range. Try to confirm that the device really is
// a touch screen.
if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { //也就是这个BTN_TOUCH,
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver? 仍是单点的简单
} else if (test_bit(BTN_TOUCH, device->keyBitmask)
&& test_bit(ABS_X, device->absBitmask)
&& test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
}
/********************************************************************************
从上面的分析来看要肯定这个设备
多点触控须要报三个bit位
ABS_MT_POSITION_X ABS_MT_POSITION_Y BTN_TOUCH
单点触控也是三个bit位
ABS_X ABS_Y BTN_TOUCH
鼠标三个bit位
REL_X REL_Y BTN_MOUSE
********************************************************************************/
// See if this device is a joystick.游戏杆
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
if (test_bit(i, device->absBitmask)
&& (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
}
}
}
// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
if (test_bit(i, device->swBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
break;
}
}
// Configure virtual keys. 虚拟按键处理这个也很重要如今通常触摸屏上带的按键都是这么处理的
//下面会单独讲 注解5
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
status_t status = loadVirtualKeyMapLocked(device);
LOGE("Get virtualkeys\n");
if (!status) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; //给设备增长一个 键盘类
}
}
// Load the key map.
// We need to do this for joysticks too because the key layout may specify axes.
status_t keyMapStatus = NAME_NOT_FOUND;
if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
// Load the keymap for the device.
keyMapStatus = loadKeyMapLocked(device);//获取设备的keymap文件 这个对于按键设备来说比较
} //重要也比较复杂 能够百度 android keymap
// Configure the keyboard, gamepad or virtual keyboard.配置键盘类的设备
if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Register the keyboard as a built-in keyboard if it is eligible.
if (!keyMapStatus
&& mBuiltInKeyboardId == -1
&& isEligibleBuiltInKeyboard(device->identifier,
device->configuration, &device->keyMap)) {
mBuiltInKeyboardId = device->id;
}
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}
// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
break;
}
}
}
/********************************************************************************
注意上面device->classes的赋值方式 (除了joystick)其余都是 “|=” 也就是说一个设备其实能够
识别出多个类这也是为何一个触摸屏能够发送按键指令的缘由
********************************************************************************/
//有些设备不支持 好比有些传感器走的也是input设备 可是他们由单独的传感器模块处理而不是有eventhub,所以这里他们会被排除掉。
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
LOGV("Dropping device: id=%d, path='%s', name='%s'",
deviceId, devicePath, device->identifier.name.string());
delete device;
return -1;
}
//判断是内部设备仍是外部设备看代码断定是外部设备有两个条件一是配置文件中有
//"device.internal"这个配置项就是内部设备其余为外部设备,一是总线类型是usb 或者 蓝牙就是外部设备。
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
}
//注册一个epoll来监听这个设备的事件。
//epoll是内核提供的一个监听设备的一个方法跟select相似不过比select更高效并且没有个数的限制
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
LOGE("Could not add device fd to epoll instance. errno=%d", errno);
delete device;
return -1;
}
LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
toString(mBuiltInKeyboardId == deviceId));
mDevices.add(deviceId, device);//将设备加入到已打开设备链表中
device->next = mOpeningDevices;
mOpeningDevices = device;
return 0;
}
下面对两个小方面作一下说明:
1.打开配置文件,上面函数调用的 loadConfigurationLocked(device);
void EventHub::loadConfigurationLocked(Device* device) {
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (device->configurationFile.isEmpty()) { LOGD("No input device configuration file found for device '%s'.", device->identifier.name.string()); } else { status_t status = PropertyMap::load(device->configurationFile, &device->configuration); if (status) { LOGE("Error loading input device configuration file for device '%s'. " "Using default configuration.", device->identifier.name.string()); } } } 调用getInputDeviceConfigurationFilePathByDeviceIdentifier(device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); 这个函数的定义在android\frameworks\base\libs\ui\Input.cpp中 String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type) { if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { if (deviceIdentifier.version != 0) { // Try vendor product version. //首先从厂商编号、设备编号和设备驱动版本号去获取设备文件 String8 versionPath(getInputDeviceConfigurationFilePathByName( String8::format("Vendor_%04x_Product_%04x_Version_%04x", deviceIdentifier.vendor, deviceIdentifier.product, deviceIdentifier.version), type)); if (!versionPath.isEmpty()) { return versionPath; } } // Try vendor product. String8 productPath(getInputDeviceConfigurationFilePathByName( String8::format("Vendor_%04x_Product_%04x", deviceIdentifier.vendor,deviceIdentifier.product),//若是没有成功就从厂商编号 type)); //和设备编号去获取 if (!productPath.isEmpty()) { return productPath; } } // Try device name. return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);//若是尚未的话就 //从设备名去获取 } 上面调用getInputDeviceConfigurationFilePathByName()这个函数也在这个文件里,由于很简单就不贴出来它 的做用是首先从ANDROID_ROOT/usr/idc目录下去找相应名字的文件并返回完整的路径名,若是找不到就从 ANDROID_DATA/system/devices/idc下面去找,这里ANDROID_ROOT通常指的是/system目录 ANDROID_DATA 通常指/data目录.总结来看安卓为输入设备打开配置文件依次会访问 /system/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc /system/usr/idc/Vendor_XXXX_Product_XXXX.idc /system/usr/idc/DEVICE_NAME.idc /data/system/devices/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc /data/system/devices/idc/Vendor_XXXX_Product_XXXX.idc /data/system/devices/idc/DEVICE_NAME.idc 咱们之后在作输入设备配置文件的时候必定要注意顺序,别改了半天很差用。官网上也有这个的说明上地址 http://source.android.com/devices/tech/input/input-device-configuration-files.html 2.打开按键映射文件,上面调用loadKeyMapLocked(device); status_t EventHub::loadKeyMapLocked(Device* device) { return device->keyMap.load(device->identifier, device->configuration); } 这里调用keyMap.load()它的定义在 android\frameworks\base\libs\ui\Keyboard.cpp status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if(deviceConfiguration->tryGetProperty(String8("keyboard.layout"),//查找配置文件中keyboard.layout keyLayoutName)) { //项 来加载layout文件 status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); if (status == NAME_NOT_FOUND) { LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), //查找配置文件中 keyCharacterMapName)) { //keyboard.characterMap项 来加载characterMap文件 status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); if (status == NAME_NOT_FOUND) { LOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } if (isComplete()) { return OK; } } // Try searching by device identifier. if (probeKeyMap(deviceIdenfifier, String8::empty())) { return OK; //若是没有成功就靠 厂商id 设备id 驱动版本 等来查找 } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { //若是尚未成功就打开"Generic" return OK; } // Try the Virtual key map as a last resort. if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { //尚未就打开 "Virtual" return OK; } // Give up! LOGE("Could not determine key map for device '%s' and no default key maps were found!", deviceIdenfifier.name.string()); return NAME_NOT_FOUND; } 总结 从上面能够看出安卓打开layout文件的依次顺序为 config 定义的 /system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl /system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl /system/usr/keylayout/DEVICE_NAME.kl /data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl /data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl /data/system/devices/keylayout/DEVICE_NAME.kl /system/usr/keylayout/Generic.kl /data/system/devices/keylayout/Generic.kl 官方介绍网址http://source.android.com/devices/tech/input/key-layout-files.html characterMap的打开顺序为 config定义的 /system/usr/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm /system/usr/keychars/Vendor_XXXX_Product_XXXX.kcm /system/usr/keychars/DEVICE_NAME.kcm /data/system/devices/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm /data/system/devices/keychars/Vendor_XXXX_Product_XXXX.kcm /data/system/devices/keychars/DEVICE_NAME.kcm /system/usr/keychars/Generic.kcm /data/system/devices/keychars/Generic.kcm /system/usr/keychars/Virtual.kcm /data/system/devices/keychars/Virtual.kcm 官方介绍网址http://source.android.com/devices/tech/input/key-character-map-files.html 注解3 这个设计的epoll的操做 在EventHub::EventHub(void)中有以下代码 mEpollFd = epoll_create(EPOLL_SIZE_HINT); //建立一个 epoll文件 mINotifyFd = inotify_init(); // 用来监控/dev/input/目录下的文件改动 struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY;//添加的监控设备所要发送的事件类型 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); //将mINotifyFd添加到mEpollFd的监控中 在EventHub::getEvents中有以下代码 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); //取出mEpollFd的事件放在数组mPendingEventItems中 注解4 在EventHub::EventHub(void)中有以下代码 int wakeFds[2]; result = pipe(wakeFds); //建立管道 mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);//注册这个管道 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); //将read管道添加到mEpollFd的监控中 //这个的做用时是当向mWakeWritePipeFd写入数据时 ,系统就会经过mEpollFd发送事件,而后就能够经过 //mWakeReadPipeFd将发送的数据读出来.mWakeWritePipeFd的调用是在InputReader::requestRefreshConfiguration //中这里下面会讲到,它的做用是 唤醒整个input系统 一样的会利用EventHub::getEvents中的。 int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); //将获取的事件添加到mPendingEventItems中 注解5 关于虚拟按键配置文件,处理代码在android\frameworks\base\services\input\EventHub.cpp中 status_t EventHub::loadVirtualKeyMapLocked(Device* device) { // The virtual key map is supplied by the kernel as a system board property file. String8 path; path.append("/sys/board_properties/virtualkeys."); path.append(device->identifier.name);//虚拟按键配置文件在/sys/board_properties/virtualkeys.name中 if (access(path.string(), R_OK)) { return NAME_NOT_FOUND; } return VirtualKeyMap::load(path, &device->virtualKeyMap); } 这里调用irtualKeyMap::load(path, &device->virtualKeyMap); 在android\frameworks\base\libs\ui\VirtualKeyMap.cpp中 status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap){ *outMap = NULL; Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer);//打开文件得到tokenizer if (status) { LOGE("Error %d opening virtual key map file %s.", status, filename.string()); } else { VirtualKeyMap* map = new VirtualKeyMap(); if (!map) { LOGE("Error allocating virtual key map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map, tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; LOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status) { delete map; } else { *outMap = map; //返回 map的指针 } } delete tokenizer; } return status; } 至此打来了虚拟按键的配置文件 3、Input事件的处理 终于读取到了input事件,说道事件的处理咱们还得继续来看void InputReader::loopOnce()中的事件处理 void InputReader::loopOnce() { int32_t timeoutMillis; { 。。。。。。。。 。。。。。。。。。。 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); if (count) { processEventsLocked(mEventBuffer, count); } 。。。。。。。。。。。。。。 } 这里调用 processEventsLocked(mEventBuffer, count); 在android\frameworks\base\services\input\InputReader.cpp文件中 void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { //循环处理全部事件 int32_t type = rawEvent->type; size_t batchSize = 1; //若是事件的类型比FIRST_SYNTHETIC_EVENT 说明这是个kernel传来的input事件 if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { //找到属于同一个设备全部事件 或者 同一设备 但类型为FIRST_SYNTHETIC_EVENT之 //前的全部事件 ,从这里能够看出若是要系统处理一次的操做,那么驱动层必须发送 //FIRST_SYNTHETIC_EVENT事件,或者形成设备切换,设备切换不是咱们能控制的所以我 //们必须发送FIRST_SYNTHETIC_EVENT事件来告诉系统此次操做完成了。 if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } #if DEBUG_RAW_EVENTS LOGD("BatchSize: %d Count: %d", batchSize, count); #endif processEventsForDeviceLocked(deviceId, rawEvent, batchSize);//处理这些事件 注解7 } else { //这个是设备变化的事件 switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: //增长设备 addDeviceLocked(rawEvent->when, rawEvent->deviceId); //注解6 break; case EventHubInterface::DEVICE_REMOVED: //删除设备这个很少作说明了,就是把当前设备 从设备链表里删除 removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: //扫描设备完成 handleConfigurationChangedLocked(rawEvent->when);注 break; default: LOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } } 在这里咱们看到全部的事件都获得了处理,可是处理的方式还没看,要处理事件首先要有设备, 所以咱们先看addDeviceLocked()这个函数 注解6 关于增长设备 addDeviceLocked(rawEvent->when, rawEvent->deviceId)代码在当前文件下 void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); //获得设备名字 uint32_t classes = mEventHub->getDeviceClasses(deviceId);//获得设备类型 InputDevice* device = createDeviceLocked(deviceId, name, classes);//建立一个inputreader层的设备 device->configure(when, &mConfig, 0); //配置一些东西 ----------------------------+- device->reset(when); //复位 || || if (device->isIgnored()) {//看mapper是否添加成功了 || LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string());|| } else { || LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(), || device->getSources()); || } || || ssize_t deviceIndex = mDevices.indexOfKey(deviceId); || if (deviceIndex < 0) { || mDevices.add(deviceId, device); //添加新建的设备 || } else { || LOGW("Ignoring spurious device added event for deviceId %d.", deviceId); || delete device; || return; || } || || 这个函数里调用了createDeviceLocked() 和 configure()咱们一一来看 || createDeviceLocked()在当前文件中代码 <------------------------------------ | InputDevice* InputReader::createDeviceLocked(int32_t deviceId, | const String8& name, uint32_t classes) { | InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);//建立一个新设备 | | // External devices. | if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { //为外部设备 设置专门属性 | device->setExternal(true); | } | //为switch设备添加mapper文件inputmapper文件是事件的映射文件,负责把事件处理后输送给相应的上层app | //这个设备不多用到咱们就暂时不分析了代码在InputReader.cpp中 须要的本身看一下 | // Switch-like devices. | if (classes & INPUT_DEVICE_CLASS_SWITCH) { | device->addMapper(new SwitchInputMapper(device)); | } | | // Keyboard-like devices. | uint32_t keyboardSource = 0; | int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; | if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { | //设置按键类设备的mapper属性这里添加的mapper文件只有基本属性,并无具体的内容具体配置是 | //在config中进行的 | keyboardSource |= AINPUT_SOURCE_KEYBOARD; | } | if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { | keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; | } | if (classes & INPUT_DEVICE_CLASS_DPAD) { | keyboardSource |= AINPUT_SOURCE_DPAD; | } | if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { | keyboardSource |= AINPUT_SOURCE_GAMEPAD; | } | | if (keyboardSource != 0) { //为按键类设备添加mapper文件 | device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); | } | | // Cursor-like devices. | if (classes & INPUT_DEVICE_CLASS_CURSOR) { //为鼠标类设备添加mapper 文件 | device->addMapper(new CursorInputMapper(device)); | } | | // Touchscreens and touchpad devices. | if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { //触控类添加mapper文件 | device->addMapper(new MultiTouchInputMapper(device)); | } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { | device->addMapper(new SingleTouchInputMapper(device)); | } | | // Joystick-like devices. | if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { //游戏杆类添加mapper文件 | device->addMapper(new JoystickInputMapper(device)); | } | | return device; | } | | 对于上面的addMapper这个函数 | void InputDevice::addMapper(InputMapper* mapper) { | mMappers.add(mapper); | } | | 这里调用了mMappers.add(mapper);我没找到这add方法的实现代码在哪?哪位大神能够提示一下最好。在此先谢过 | 不过createDeviceLocked这个函数仍是很简单的,就是一些新建设备和mapper文件,具体的操做都没有涉及到 | | 下面看InputDevice::configure 也在这个文件中 <---------------------------- void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes){ mSources = 0; if (!isIgnored()) { //mapper文件不为空 if (!changes) { // first time only mContext->getEventHub()->getConfiguration(mId, &mConfiguration); //找到相应的idc文件 } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->configure(when, config, changes); mSources |= mapper->getSources(); } } } 上面调用的getConfiguration()在 EventHub.cpp中 先看getConfiguration()这个函数的做用是,返回设备的配置文件(即idc文件)指针。 void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->configuration) { *outConfiguration = *device->configuration; } else { outConfiguration->clear(); } } 调用mapper->configure(when, config,changes)这里跟每一个设备有关,这里只能分开来说,咱们从多点触控看起吧 多点触控的mapper定义为为MultiTouchInputMapper,可是这个类里面没有configure的定义那么我只能来看他的父类 TouchInputMapper中configure的定义代码在InputReader.cpp中 void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); mConfig = *config; if (!changes) { // first time only // Configure basic parameters. configureParameters(); //见下面 | V /************************************************************************************************ 上面调用的configureParameters()函数 void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not supportdistinct //基于指针的配置并不明显的支持多点触控,这里的配置可以准确的配置两点或以上设备 // multitouch. The spot-based presentation relies on being able to accurately // locate two or more fingers on the touch pad. mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(),INPUT_PROP_SEMI_MT) //从驱动里肯定device 是多点触控 仍是指针,仍是点设备 ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS; String8 gestureModeString; //配置文件中找touch.gestureMode这个条目 来肯定设备的类型 if(getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), gestureModeString)) { if (gestureModeString == "pointer") { //若是指针 mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER; } else if (gestureModeString == "spots") { //点设备 mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS; } else if (gestureModeString != "default") { //默认 LOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); } } //从驱动文件里肯定 触控设备的类型 if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { // The device is a touch screen. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; //触摸屏 } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { // The device is a pointing device like a track pad. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备(多指鼠标) } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) //传送的坐标是相对坐标 || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { //y也是相对坐标 // The device is a cursor device with a touch pad attached. // By default don't use the touch pad to move the pointer. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; //那就是触摸板 } else { // The device is a touch pad of unknown purpose. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备 } String8 deviceTypeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), deviceTypeString)) { //从配置文件中肯定设备类型 if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; //触摸屏 } else if (deviceTypeString == "touchPad") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; //触摸板 } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备 } else if (deviceTypeString != "default") { LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); } } mParameters.orientationAware = mParameters.deviceType ==Parameters::DEVICE_TYPE_TOUCH_SCREEN; getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), mParameters.orientationAware); //idc文件中找"touch.orientationAware"这个条目来肯定屏幕的方向 mParameters.associatedDisplayId = -1; mParameters.associatedDisplayIsExternal = false; if (mParameters.orientationAware || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { mParameters.associatedDisplayIsExternal = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && getDevice()->isExternal(); mParameters.associatedDisplayId = 0; } } *******************************************************************************************/ // Configure common accumulators.配置光标和按键加速,都是根据驱动文件或者idc文件 mCursorScrollAccumulator.configure(getDevice()); mTouchButtonAccumulator.configure(getDevice()); // Configure absolute axis information.将全部坐标相关初始值清除 代码在本文件中的void RawPointerAxes::clear() configureRawPointerAxes(); //而后调用voidMultiTouchInputMapper::configureRawPointerAxes()也在本文件中,它是从 //驱动文件里面找到一些配置而后读取出来 这些代码就不贴出来了太多了 并且意义不大 // Prepare input device calibration. 准备 输入设备标准把硬件信息 加入到 创建的虚拟设备中例如 parseCalibration(); //分辨率 屏幕方向 显示区域等信息 代码很长不贴了 resolveCalibration(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { // Update pointer speed. //校准 指针速度 mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); //简单的校准参数赋值 代码很简单都在本文件中 这里就不贴了 } bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when,&resetNeeded);---------------------------------------------------------- } | | if (changes && resetNeeded) { | //Send reset, unless this is the first time the device has beenconfigured,除非这个设备是第一次配置, | //in which case the reader will call reset itself after all mappers areready不然在这里它将被reset一次 | getDevice()->notifyReset(when); | } | } | | /********************************************************************************************** <----- 下面看 configureSurface(when, &resetNeeded); 在InputReader.cpp中 void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; // Determine device mode. 经过设备的类型来肯定mSource和mDeviceMode。 if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { mSource = AINPUT_SOURCE_MOUSE; mDeviceMode = DEVICE_MODE_POINTER; } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && mParameters.associatedDisplayId >= 0) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; } else { mSource = AINPUT_SOURCE_TOUCHPAD; mDeviceMode = DEVICE_MODE_UNSCALED; } // Ensure we have valid X and Y axes.从驱动中读出来的配置中 x和y的值 是有效的 if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { LOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " "The device will be inoperable.", getDeviceName().string()); mDeviceMode = DEVICE_MODE_DISABLED; return; } // Get associated display dimensions. if (mParameters.associatedDisplayId >= 0) { if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId //获得显示屏的分辨率 代码在本文件中 mParameters.associatedDisplayIsExternal, | &mAssociatedDisplayWidth, &mAssociatedDisplayHeight, | &mAssociatedDisplayOrientation)) { | LOGI(INDENT "Touch device '%s' could not query the properties of its associated " | "display %d. The device will be inoperable until the display size " | "becomes available.", | getDeviceName().string(), mParameters.associatedDisplayId); | mDeviceMode = DEVICE_MODE_DISABLED; | return; | } | } V /*********************************************************************************************** bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external, int32_t* width, int32_t* height, int32_t* orientation) const { if (displayId == 0) { const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay; //这里的关键是 mExternalDisplay和mInternalDisplay在哪里初始化的值 if (info.width > 0 && info.height > 0) { //其实这是在另一个进程里设置的 过程比较复杂 if (width) { //参考http://wenku.baidu.com/view/1c25e14a2e3f5727a5e9621f.html *width = info.width; } if (height) { *height = info.height; } if (orientation) { *orientation = info.orientation; } return true; } } return false; } ************************************************************************************************/ // Configure dimensions. 根据上面肯定的mDeviceMode 来肯定 实际可用的分辨率, int32_t width, height, orientation; if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { width = mAssociatedDisplayWidth; //真实的分辨率 height = mAssociatedDisplayHeight; orientation = mParameters.orientationAware ? mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0; } else { //驱动中读出来的分辨率通过计算获得的 width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; orientation = DISPLAY_ORIENTATION_0; } // If moving between pointer modes, need to reset some state. //设备类型发生了改变这说明前面的配置可能发生某种意外 清除一些状态 下面从新来配置 bool deviceModeChanged; if (mDeviceMode != oldDeviceMode) { deviceModeChanged = true; mOrientedRanges.clear(); } // Create pointer controller if needed. if (mDeviceMode == DEVICE_MODE_POINTER || (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { if (mPointerController == NULL) { mPointerController = getPolicy()->obtainPointerController(getDeviceId()); //创建一个pointer controller //pointercontroller 是神马东西呢咱们能够找到他们的代码 //android\frameworks\base\services\input\PointerController.cpp中,这里就不分析代码了,实在太多了,仅 //对它的做用说明一下:当咱们触摸屏幕或者移动鼠标时,咱们有时候须要在屏幕上 触摸点或者鼠标光标的位置, //pointer controller 就是同步坐标和显示位置用的 } } else { mPointerController.clear(); } char hwrotBuf[PROPERTY_VALUE_MAX]; int32_t hwrotation; property_get("ro.sf.hwrotation", hwrotBuf, "0"); hwrotation = atoi(hwrotBuf) / 90; orientation = (orientation + hwrotation ) % 4; if (hwrotation == DISPLAY_ORIENTATION_90 || hwrotation == DISPLAY_ORIENTATION_270) { int tmp = width; width = height; height = tmp; } bool orientationChanged = mSurfaceOrientation != orientation; if (orientationChanged) { mSurfaceOrientation = orientation; } bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height; if (sizeChanged || deviceModeChanged) { LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d, mode is %d", getDeviceId(), getDeviceName().string(), width, height, mDeviceMode); mSurfaceWidth = width; mSurfaceHeight = height; // Configure X and Y factors. mXScale = float(width) / (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1); mYScale = float(height) / (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1); mXPrecision = 1.0f / mXScale; mYPrecision = 1.0f / mYScale; mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;//若是分辨率有了改变就须要从新配置一些参数 mOrientedRanges.x.source = mSource; mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; mOrientedRanges.y.source = mSource; configureVirtualKeys(); //配置虚拟按键 代码在本文件中 | V /***************************************************************************************** void TouchInputMapper::configureVirtualKeys() { Vector<VirtualKeyDefinition> virtualKeyDefinitions; getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); //这里有个新数据类型Vector,他的做用咱们作个说明 //vector是C++标准模板库中的部份内容,中文偶尔译做“容器”,但并不许确。它是一个多功能的, //可以操做多种数据结构和算法的模板类和函数库。vector之因此被认为是一个容器,是由于它可以 //像容器同样存放各类类型的对象,简单地说,vector是一个可以存听任意类型的动态数组,可以增 //加和压缩数据。 mVirtualKeys.clear(); if (virtualKeyDefinitions.size() == 0) { return; } mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); int32_t touchScreenLeft = mRawPointerAxes.x.minValue; //肯定按键的 坐标和大小 int32_t touchScreenTop = mRawPointerAxes.y.minValue; int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; //获得按键的定义(虚拟按键配置文件中读出来的) mVirtualKeys.add(); //添加这个按键 VirtualKey& virtualKey = mVirtualKeys.editTop(); virtualKey.scanCode = virtualKeyDefinition.scanCode; int32_t keyCode; uint32_t flags; if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, & keyCode, & flags)) { LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); mVirtualKeys.pop(); // drop the key 失败了。。。 continue; } virtualKey.keyCode = keyCode; virtualKey.flags = flags; // convert the key definition's display coordinates into touch coordinates for a hitbox int32_t halfWidth = virtualKeyDefinition.width / 2; int32_t halfHeight = virtualKeyDefinition.height / 2; //按键的上下左右坐标 virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; } } ********************************************************************************************/ 剩下的就 很少说了 全是参数的配置 。。。。。。。。。 。。。。。。。。。 。。。。。。。。。 } *************************************************************************************************/ 注解7: 关于InputReader中国事件的处理,input事件的处理代码在当前文件下 void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); //获得发生input事件的设备索引 if (deviceIndex < 0) { LOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); //获得device if (device->isIgnored()) { //LOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); //事件处理 | } V /************************************************************************************************ 这里调用>process(rawEvents, count);来处理代码在 android\frameworks\base\services\input\InputReader.cpp中 void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. 让每一个设备的 mapper处理相应的input事件 // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { 。。。。。 if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { mDropUntilNextSync = false; ......... } else { ............. } } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) { LOGI("Detected input event buffer overrun for device %s.", mName.string()); mDropUntilNextSync = true; reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); //经过每一个设备mapper 来处理事件咱们来看多点触控的 } | } | } | } | V 上面调用的 在本文件中 void MultiTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); } 继续看mMultiTouchMotionAccumulator.process(rawEvent); 也在本文件中 void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { //只处理 EV_ABS EV_SYN 和 SYN_MT_REPORT bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->scanCode == ABS_MT_SLOT) { //多点触控槽这个我也不知道怎么翻译好,可是具体 mCurrentSlot = rawEvent->value; //做用我知道的很清楚指的是多点触控所支持的最大点数 newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } //触摸屏所支持的最大点数设置错误 就报个错 if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { #if DEBUG_POINTERS if (newSlot) { LOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %d; ignoring this slot.", mCurrentSlot, mSlotCount - 1); } #endif } else { Slot* slot = &mSlots[mCurrentSlot]; switch (rawEvent->scanCode) { //解析全部的合法的多点触控数据 case ABS_MT_POSITION_X: //X坐标 slot->mInUse = true; slot->mAbsMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y://Y坐标 slot->mInUse = true; slot->mAbsMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: //椭圆形接触点的长轴 这个值会随着压力的增大而增大 slot->mInUse = true; slot->mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: //椭圆形接触点的短轴 slot->mInUse = true; slot->mAbsMTTouchMinor = rawEvent->value; slot->mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: //把造成触点的手指 当作一个椭圆 它的 长轴 个一般是个常量 slot->mInUse = true; slot->mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: //把造成触点的手指 当作一个椭圆 它的 短轴 slot->mInUse = true; slot->mAbsMTWidthMinor = rawEvent->value; slot->mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: //椭圆的方向 slot->mInUse = true; slot->mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: //触点的ID if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot->mInUse = false; } else { slot->mInUse = true; slot->mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: //压力 slot->mInUse = true; slot->mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: //触点 悬停 距离 slot->mInUse = true; slot->mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: //类型 slot->mInUse = true; slot->mAbsMTToolType = rawEvent->value; slot->mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } voidMultiTouchInputMapper::process()执行完了,比较坑爹的是MultiTouchInputMapper的父类还有一个 process接下来系统会运行这个函数 void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { sync(rawEvent->when); } } 这个函数会处理sync事件 void TouchInputMapper::sync(nsecs_t when) { // Sync button state. mCurrentButtonState = mTouchButtonAccumulator.getButtonState() //同步按键状态 | mCursorButtonAccumulator.getButtonState(); // Sync scroll state. mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); //滚动条状态 mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); //清除之前信息 // Sync touch state. bool havePointerIds = true; mCurrentRawPointerData.clear(); syncTouch(when, &havePointerIds);-------- | 。。。。。。 | 。。。。。。 V /************************************************************************************* void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { const MultiTouchMotionAccumulator::Slot* inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); if (!inSlot->isInUse()) { continue; } if (outCount >= MAX_POINTERS) { ........ break; // too many fingers! } //把事件信息放到 mCurrentRawPointerData.pointers中 供后面使用 RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); outPointer.touchMajor = inSlot->getTouchMajor(); outPointer.touchMinor = inSlot->getTouchMinor(); outPointer.toolMajor = inSlot->getToolMajor(); outPointer.toolMinor = inSlot->getToolMinor(); outPointer.orientation = inSlot->getOrientation(); outPointer.distance = inSlot->getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } } bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. //看看 点的ID是否有效 if (*outHavePointerIds) { int32_t trackingId = inSlot->getTrackingId(); int32_t id = -1; if (trackingId >= 0) { for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { uint32_t n = idBits.clearFirstMarkedBit(); if (mPointerTrackingIdMap[n] == trackingId) { id = n; } } if (id < 0 && !mPointerIdBits.isFull()) { id = mPointerIdBits.markFirstUnmarkedBit(); mPointerTrackingIdMap[id] = trackingId; } } if (id < 0) { *outHavePointerIds = false; mCurrentRawPointerData.clearIdBits(); newPointerIdBits.clear(); } else { outPointer.id = id; mCurrentRawPointerData.idToIndex[id] = outCount; mCurrentRawPointerData.markIdBit(id, isHovering); newPointerIdBits.markBit(id); } } outCount += 1; } mCurrentRawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); } ************************************************************************************/ // Reset state that we will compute below. mCurrentFingerIdBits.clear(); //先清除一些数据 mCurrentStylusIdBits.clear(); mCurrentMouseIdBits.clear(); mCurrentCookedPointerData.clear(); if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. //设备无效就把数据清除 mCurrentRawPointerData.clear(); mCurrentButtonState = 0; } else { // Preprocess pointer data. //不然就处理他们 if (!havePointerIds) { assignPointerIds(); } // Handle policy on initial down or hover events. uint32_t policyFlags = 0; bool initialDown = mLastRawPointerData.pointerCount == 0 && mCurrentRawPointerData.pointerCount != 0; bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; if (initialDown || buttonsPressed) { //若是第一次摁下 // If this is a touch screen, hide the pointer on an initialdown.若是是个触摸屏,隐藏这个点 if (mDeviceMode == DEVICE_MODE_DIRECT) { getContext()->fadePointer(); } // Initial downs on external touch devices should wake thedevice.若是是外部设备就唤醒整个系统 // We don't do this for internal touch screens to prevent them from waking // up in your pocket.//内部设备不用唤醒,由于有时候你仅仅是把设备放进口袋里 // TODO: Use the input device configuration to control this behavior more finely. if (getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } } 。。。。。。。。。 // Cook pointer data. This call populates the mCurrentCookedPointerData structure // with cooked pointer data that has the same ids and indices as the raw data. // The following code can use either the raw or cooked data, as needed. cookPointerData();//根据当前屏幕显示状态进行坐标转换关于这个官网有个很详细的介绍这里就不作说 //明了给出网址http://source.android.com/devices/tech/input/touch-devices.html // Dispatch the touches either directly or by translation through a pointer on screen. if (mDeviceMode == DEVICE_MODE_POINTER) { //若是是鼠标 。。。。。。。。。。。。。。 // Stylus takes precedence over all tools, then mouse, then finger.优先级 笔《鼠标《手指 PointerUsage pointerUsage = mPointerUsage; if (!mCurrentStylusIdBits.isEmpty()) { mCurrentMouseIdBits.clear(); mCurrentFingerIdBits.clear(); pointerUsage = POINTER_USAGE_STYLUS; } else if (!mCurrentMouseIdBits.isEmpty()) { mCurrentFingerIdBits.clear(); pointerUsage = POINTER_USAGE_MOUSE; } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { pointerUsage = POINTER_USAGE_GESTURES; } dispatchPointerUsage(when, policyFlags, pointerUsage);//分发这个事件 这里不作说明咱们从下 //面touch设备看起最终他俩是一个做用就是把事件放入到 待处理的队列中 } else { if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && mPointerController != NULL) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->setButtonState(mCurrentButtonState); mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, mCurrentCookedPointerData.touchingIdBits); } dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); --------------------- dispatchHoverEnterAndMove(when, policyFlags); | } V /********************************************************************************************** void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { 。。。。。。。。。。。。。。。。。。。。。。 if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event.点ID没有变化 那么这是一个MOVE 事件 // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } else { //有多是 up down move 等事件 。。。。。。。。。。。。。。。 // Dispatch pointer up events. //up事件处理 while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { //move事件处理 LOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.clearFirstMarkedBit(); dispatchedIdBits.markBit(downId); if (dispatchedIdBits.count() == 1) { // First pointer is going down. Set down time. mDownTime = when; } dispatchMotion(when, policyFlags, mSource, //down事件处理 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } } 上面函数分发事件统一调用了dispatchMotion()这个函数咱们来看这个 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { 。。。。。。。。。。。 。。。。。。。。。。。。。 NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, flags, metaState, buttonState, edgeFlags, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); 这里调用TouchInputMapper::getListener()->notifyMotion(&args)TouchInputMapper::getListener()调用 mContext->getListener(), 此mContext为InputReader::mContext,因此其getListener()返回的则为 InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion 最后咱们找到实现代码在android\frameworks\base\services\input\InputListener.cpp中 void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); } 这个函数是把 整理好的事件 放入到队列里。 ************************************************************************************************/ 。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。 } ************************************************************************************************/ 咱们回头看 void InputReader::loopOnce() { int32_t timeoutMillis; { // acquire lock 。。。。。。。。。。。。。。 processEventsLocked(mEventBuffer, count); 。。。。。。。。。。。。。。。。。。。。 // Flush queued events out to the listener.将队列里的事件发送到给各个listener // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. mQueuedListener->flush(); } 到了这里InputReader中的事件处理已经完成了,总的来说,他们是把从kernel总读取的事件通过一系列的变换和 分类,分别存到相应的mQueuedListener::mArgsQueue队列中,而后将他们再分发出去。总结的很简单,但中间涉 及的 东西不少,上面也仅仅是简介而已。 上面我只分析了 多点触控的事件处理,其余设备的起始也相似,就很少作说明了。 接下来终于能够该看 InputDispatcher了。 咱们接上面的mQueuedListener->flush();代码在android\frameworks\base\services\input\InputListener.cpp中 void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); delete args; } mArgsQueue.clear(); } 这个函数是执行每一个队列里的notify函数,咱们先看这个参数mInnerListener,它是关系到Dispatcher和Reader 联系的重要桥梁。 咱们来分析为何。他是在QueuedInputListener类实例化的时候传进来的,代码 QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : mInnerListener(innerListener) { } 那么QueuedInputListener实例化在哪呢,继续找咱们发现 他也是一个参数,在InputReader构造函数里里 InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); 不行的时发现这里listener仍是一个参数,咱们继续找InputReader的实例化代码,在InputManager的代码里 InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); } 从这里看出mInnerListener这个参数就是mDispatcher,到了这里终于找到了Dispatcher和Reader的联系了。 咱们继续看, args->notify()这个函数,文件里有不少类的args,咱们以NotifyKeyArgs为例子进行说明。 void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this); } 咱们看到这里调用了Dispatcher的函数notifyKey(this)咱们找到这个函数的实现代码 在android\frameworks\base\services\input\InputDispatcher.cpp中 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { 。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。。。。。. if (!motionEntry->canAppendSamples(args->action, //将事件复制到mInboundQueue中 args->pointerCount, args->pointerProperties)) { // Last motion event in the queue for this device and source is // not compatible for appending new samples. Stop here. goto NoBatchingOrStreaming; } 。。。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。。。。。。。。 if (needWake) { mLooper->wake(); } } 这里调用mLooper->wake(); 终于能够执行InputDispatcher的线程了,在这以前的全部动做都是在 InputReader中执行的。 下面能够看 mDispatcher->dispatchOnce();这个函数了 在android\frameworks\base\services\input\InputDispatcher.cpp中 void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); dispatchOnceInnerLocked(&nextWakeupTime); //事件处理---------------------------------- | if (runCommandsLockedInterruptible()) { | nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately | } | } // release lock | | // Wait for callback or timeout or wake. (make sure we round up, not down) | nsecs_t currentTime = now(); | int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); | mLooper->pollOnce(timeoutMillis); | | } V | | 这里调用的mLooper->pollOnce(timeoutMillis); 在android\frameworks\base\libs\utils\Looper.cpp中 | int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { | int result = 0; | for (;;) { | while (mResponseIndex < mResponses.size()) { | const Response& response = mResponses.itemAt(mResponseIndex++); | ALooper_callbackFunc callback = response.request.callback; | if (!callback) { | int ident = response.request.ident; | int fd = response.request.fd; | int events = response.events; | void* data = response.request.data; | 。。。。。 | if (outFd != NULL) *outFd = fd; | if (outEvents != NULL) *outEvents = events; | if (outData != NULL) *outData = data; | return ident; | } | } | | if (result != 0) { | 。。。。 | if (outFd != NULL) *outFd = 0; | if (outEvents != NULL) *outEvents = NULL; | if (outData != NULL) *outData = NULL; | return result; | } | | result = pollInner(timeoutMillis);注意这里 这个函数会致使线程阻塞 一是超时 一是 epoll | } | | } | | V | | int Looper::pollInner(int timeoutMillis) { | | 。。。。。。。。。。。。。。。。。。。。。 | int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);//超时阻塞 | 。。。。。。。。。。。。。。。。 | 。。。。。。。。。。。 | int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);//epoll阻塞 | 。。。。。。。。。. | 。。。。。。。。 | } | | | | void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { <------------------------ nsecs_t currentTime = now(); 。。。。。。。。。。。。。。 mInboundQueue.dequeue(entry);//从事件队列里面取出事件 mPendingEvent = entry; } // Poke user activity for this event. if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } } // Now we have an event to dispatch.咱们取得了 分发的事件 // All events are eventually dequeued and processed this way, even if we intend to drop them. //全部从队列 里取出的事件都必须用这种方法处理,甚至这是一个要被丢弃的事件 。。。。。。。。。。。。。。。。。。。。。。。 switch (mPendingEvent->type) { //根据事件的类型分别分发下去 case EventEntry::TYPE_CONFIGURATION_CHANGED: { 。。。。。。。。。 case EventEntry::TYPE_DEVICE_RESET: { 。。。。。。。。。。 case EventEntry::TYPE_KEY: { 。。。。。。。。 case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); //分发motion事件 break; | } | | default: | LOG_ASSERT(false); | break; | } | 。。。。。。。。。。。。。。。。。。。 | } | V bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { 。。。。。。。。。。。。。。。。。。。。。。。。 dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);分发事件 return true; | } | V void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, 。。。。。。。。。。。。。。。。 prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, resumeWithAppendedMotionSample); 。。。。。。。。。。。。。。。。 | } | V void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, bool resumeWithAppendedMotionSample) { 。。。。。。。。。。。。。。。。。。。。。。。。。 //建立DispatchEntry对象并把它增长到 //Connection::outboundQueue队列中。 enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget, resumeWithAppendedMotionSample); } | V void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, bool resumeWithAppendedMotionSample) { 。。。。。。。。。。。。。。。。。。。。。。。。 if (wasEmpty && !connection->outboundQueue.isEmpty()) { activateConnectionLocked(connection.get()); //把当前Connection增长到InputDispatcher::mActiveConnections链表中 startDispatchCycleLocked(currentTime,connection); //Connection::inputPublisher.publishMotionEvent来发布事件到ashmem buffer中, //调用Connection::inputPublisher.sendDispatchSignal发送一个dispatch信号到InputConsumer通知它 //有了一个新的消息。 } } 当咱们发送了signal之后,相应的app就会收到这个signal,而后就会来取出相应的事件来处理。到这里事件的分发 就算已经完成了。 总结一下,总的来说android层面input处理流程很顺,没有过多的分支,看起来其实相对简单,可是对于我这中新 手仍是颇有难度,有了分析这个的基础,之后再分析更可贵 系统也就不会以为特别的累了。 下面咱们还有Kernel层 的input分析,放到另外一个文档里面,