Input事件流程

来自个人维基
跳转至: 导航搜索

目录

一、开机时input机制创建

开机时会创建 system_server,然后在其中创建service,下面这里是 WindowManagerService的创建。

这里没有显式的使用 new创建,而是调用了类中静态函数 WindowManagerService.main,同时我们也看到 WindowManagerService的构建函数为private类型:

    private WindowManagerService(Context context, PowerManagerService pm,
            DisplayManagerService displayManager, InputManagerService inputManager,
            Handler uiHandler,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) 
    ...

其实这是非常常见的单实例类,这里不过多描述,继续看:

SystemServer.java

class ServerThread extends Thread {
        ...
    @Override
    public void run() {
        ...
        // Critical services...
        try {
            Slog.i(TAG, "Entropy Service");
            ServiceManager.addService("entropy", new EntropyService());
            ...
            Slog.i(TAG, "Window Manager");
            wm = WindowManagerService.main(context, power,
                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                    !firstBoot);  //HERE
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
        ...

进入该 main函数:

WindowManagerService.java

    public static WindowManagerService main(Context context,
            PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) {
        WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs);  //HERE
        thr.start();  //HERE
 
        synchronized (thr) {
            while (thr.mService == null) {
                try {
                    thr.wait();
                } catch (InterruptedException e) {
                }
            }
            return thr.mService;
        }
    }

创建了WMThread并start,呵呵,看到start应该条件反射地想到run了:

    static class WMThread extends Thread {
        ...
        public void run() {
            Looper.prepare();
            WindowManagerService s = new WindowManagerService(mContext, mPM,
                    mHaveInputMethods, mAllowBootMessages);  //HERE
            ...
            synchronized (this) {
                mService = s;
                notifyAll();
            }
            Looper.loop();
        }
    }

果然,是在这里创建了 WindowManagerService,继续跟进:

    private WindowManagerService(Context context, PowerManagerService pm,
            boolean haveInputMethods, boolean showBootMsgs) {
        ...
        mInputManager = new InputManager(context, this); //HERE
        PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
        ...
    }

嗯,终于看到与 "Input"相关的东东了:InputManager,看名字应该是 Input事件的管理类。

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());  //HERE
 
        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
    }

构建函数很简单,无非是一些成员变量的赋值,除此之外就是两个函数:nativeInit和Watchdog.getInstance().addMonitor(this)。第一个函数我们要深入分析才知道干了些啥;第个二则是将此实例加入Watchdog的监视列表mMonitors.

com_android_server_InputManager.cpp

    { "nativeInit", "(Landroid/content/Context;"
            "Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
            (void*) android_server_InputManager_nativeInit },
...
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);  //HERE
    } else {
        LOGE("Input manager already initialized.");
        jniThrowRuntimeException(env, "Input manager already initialized.");
    }
}

可以看到开始转入了 native环境,并在这里创建了 NativeInputManager,同时把 mContext, mCallbacks 和 looper.getQueue()作为参数传入其中。

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject callbacksObj, const sp<Looper>& looper) :
        mLooper(looper) {
    JNIEnv* env = jniEnv();
    ...
    sp<EventHub> eventHub = new EventHub();  //HERE
    mInputManager = new InputManager(eventHub, this, this);  //HERE
}

哦,原来 native层也有 InputManager

InputManager.cpp

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  //HERE
    initialize();
}
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);  //HERE
    mDispatcherThread = new InputDispatcherThread(mDispatcher);  //HERE
}

可以看到这里又创建了 InputDispatcher、InputReader的实例,同时还创建了两个线程:InputReaderThread和 InputDispatcherThread.

——这几个对象的关系是什么?我们继续分析


二、input事件的扫描

首先来看 InputReaderThread:
InputReader.h

/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
    InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();
 
private:
    sp<InputReaderInterface> mReader;
 
    virtual bool threadLoop();  //HERE
};

InputReader.cpp

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();  //HERE
    return true;
}
void InputReader::loopOnce() {
    int32_t timeoutMillis;
    { // acquire lock
        AutoMutex _l(mLock);
 
        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            refreshConfigurationLocked(changes);
        }
 
        timeoutMillis = -1;
        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
 
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  //HERE
 
    { // acquire lock
        AutoMutex _l(mLock);
 
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
        if (!count || timeoutMillis == 0) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            mNextTimeout = LLONG_MAX;
            timeoutExpiredLocked(now);
        }
    } // release lock
 
    mQueuedListener->flush();
}

我们看这一行:mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

没错,这就是最为关键的一行!

mEventHub是什么东东?如果读者留心的话,会发现在上面已经出现过了,在 NativeInputManager的构建函数中。至于这个具体是干什么用的,这里只要看其中的三个函数就能了解个大概:

EventHub.cpp

EventHub::EventHub(void) :
        mBuiltInKeyboardId(-1), mNextDeviceId(1),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
    mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
 
    mEpollFd = epoll_create(EPOLL_SIZE_HINT); //epoll就不用解释了吧,linux标准的东西
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
 
    mINotifyFd = inotify_init(); //inotify也是linux的东西,就是它能够监视某一文件,当其被创建、修改、读写时会有反映在生成的文件 mINotifyFd上
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); //这里是监视DEVICE_PATH(/dev/input)的删除、创建操作
    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
            DEVICE_PATH, errno);
 
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    //然后我们通过epoll对 mINotifyFd进行I/O侦听便可完成对 /dev/input/下文件的个数变化,如增加输入设备时可以及时加入监听列表中
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
 
    int wakeFds[2];
    result = pipe(wakeFds);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
 
    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
 
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
            errno);
 
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
            errno);
 
    eventItem.data.u32 = EPOLL_ID_WAKE;
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); //这里也是一样,增加了侦听mWakeReadPipeFd,暂且不看吧
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
            errno);
}
 
...
 
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) { //被侦听的文件有事件发生,可能是notifyId、pipefd或input设备文件
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; //取出
            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { //为notifyid,表示input设备文件被移除或添加
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true; //设置标志,后续重新扫描/dev/input/下文件
                } else {
                    LOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }
 
            if (eventItem.data.u32 == EPOLL_ID_WAKE) { //被唤醒,上面侦听 mWakeReadPipeFd的返回,先不看
                if (eventItem.events & EPOLLIN) {
                    LOGV("awoken after wake()");
                    awoken = true;
                    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);
            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); //真正的input设备,开始取数据
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity); //读出数据到readBuffer中
                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);
                    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;
                        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;
                        break;
                    }
                }
            } else {
                LOGW("Received unexpected epoll event 0x%08x for device %s.",
                        eventItem.events, device->identifier.name.string());
            }
        }
 
...
 
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); //等待新事件
 
        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;
}
 
status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];
 
    LOGV("Opening device: %s", devicePath);
 
    int fd = open(devicePath, O_RDWR);
 
...
 
    // Register with epoll.
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN; //EPOLLIN :表示对应的文件描述符可以读; 
    eventItem.data.u32 = deviceId;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { //将 devicePath加入监听
...
 
    mDevices.add(deviceId, device);
 
    device->next = mOpeningDevices;
    mOpeningDevices = device;
    return 0;
}

而devicePath则正是/dev/input/目录下的文件,openDeviceLocked的被调用关系如下:

EventHub openDeviceLocked calledby.PNG

取其中一个函数看一下:

status_t EventHub::readNotifyLocked() {
    int res;
    char devname[PATH_MAX];
    char *filename;
    char event_buf[512];
    int event_size;
    int event_pos = 0;
    struct inotify_event *event;
 
    LOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
    res = read(mINotifyFd, event_buf, sizeof(event_buf)); //取出 mINotifyFd中的数据
    if(res < (int)sizeof(*event)) {
        if(errno == EINTR)
            return 0;
        LOGW("could not get event, %s\n", strerror(errno));
        return -1;
    }
    //printf("got %d bytes of event information\n", res);
 
    strcpy(devname, DEVICE_PATH);
    filename = devname + strlen(devname);
    *filename++ = '/';
 
    while(res >= (int)sizeof(*event)) {
        event = (struct inotify_event *)(event_buf + event_pos);
        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
        if(event->len) {
            strcpy(filename, event->name); //获取文件列表文件名
            if(event->mask & IN_CREATE) {
                openDeviceLocked(devname); //加入epoll监视列表
            } else {
                LOGI("Removing device '%s' due to inotify event\n", devname);
                closeDeviceByPathLocked(devname);
            }
        }
        event_size = sizeof(*event) + event->len;
        res -= event_size;
        event_pos += event_size;
    }
    return 0;
}


三、input事件的分发

从 mEventHub中取出数据后,就要想办法快速实时地传送给framework/app,这样才能达到人机交互的目的,现在我们就来看这一部分。

InputReader.cpp

void InputReader::loopOnce() {
    ...
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
 
    { // acquire lock
        AutoMutex _l(mLock);
 
        if (count) {
            processEventsLocked(mEventBuffer, count);  //HERE
        }
        ...
    } // release lock
 
    mQueuedListener->flush();
}

取出的事件以数组的形式、按顺序存在 mEventBuffer当中,count保存了所取出的事件的个数。

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  //HERE
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED: //input设备有增加
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED: //input设备有减少
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN: //input设备扫描完成
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                LOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

上面这三个case,与 inotify监听相对应,我们这里就常规的input事件分发继续分析:

void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        LOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }
 
    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //LOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }
 
    device->process(rawEvents, count);  //HERE
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    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) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);  //HERE, 将所有类型的mapper跑一遍
                                            //ps.只有与rawEvent类型匹配的mapper才会真正作有意义的处理
                                            //因为在所有的process中均会对rawEvent进行类型判断,只有匹配才作进一步处理
            }
        }
    }
}

上面所使用的mMapper[]数组在 iNotify监控到/dev/input/下文件有增加,进而 addDeviceLocked时会有以下操作:

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-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) {
        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) {
        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); //键盘类设备
    }
 
    // Cursor-like devices.
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        device->addMapper(new CursorInputMapper(device)); //??尚不大清楚是何种输入设备
    }
 
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        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) {
        device->addMapper(new JoystickInputMapper(device));  //手柄
    }
 
    return device;
}

(一)触屏事件

以下为触屏事件对应的mapper,我们以多点触摸屏为例:

InputReader.cpp

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);
 
    mMultiTouchMotionAccumulator.process(rawEvent);
}
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);
    }
}

从上面看来,只是将rawEvent->when所传入到sync当中,那其他信息呢?

在 MultiTouchInputMapper::process中,我们看到还调用了MultiTouchMotionAccumulator::process,并传入了整个 rawEvent,"accumulator"翻译成中文是"蓄电池、累加器"的意思,那么我们现在猜想,这一步中的sync并未将当前的rawEvent进行同步分发,而是只是将此事件放在 mMultiTouchMotionAccumulator中暂时累积起来而已。

是不是这样呢? 我们再继续分析~

void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
    if (rawEvent->type == EV_ABS) {  //此次上报数据类型为 EV_ABS,
        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) { 
        //mSlotCount,这个值表示当前触摸屏支持多点触摸的最大点数,
        //由 InputDevice::addDeviceLocked -> InputDevice::configure 
        //-> TouchInputMapper::configure -> MultiTouchInputMapper::configureRawPointerAxes 
        //-> MultiTouchMotionAccumulator::configure设置,即由驱动确定
        //mCurrentSlot表示当前实际的触摸点数
            ...
        } else {
            Slot* slot = &mSlots[mCurrentSlot]; //使slot指向&mSlots[mCurrentSlot],mCureentSlot表示当前有几个手指同时点触
 
            //支持多点触控的触摸屏所报上来的数据为一个椭圆,
            //以下为此椭圆的各项参数
            //压力等
            switch (rawEvent->scanCode) {
            case ABS_MT_POSITION_X:
                slot->mInUse = true;
                slot->mAbsMTPositionX = rawEvent->value;
                break;
            case ABS_MT_POSITION_Y:
                slot->mInUse = true;
                slot->mAbsMTPositionY = rawEvent->value;
                break;
            case ABS_MT_TOUCH_MAJOR:
            ...
            }
        }
    } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) { //上报此类型数据表示一次完整的touch事件已经上报完成
        // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
        mCurrentSlot += 1;  //mCurrentSlot加1,指向下一个slot(每一个slot代表一个完整的触点信息)
    }
}

基本明白了,原来一个触点所包含的坐标、压力等信息是分别上报上来的,InputReader线程接收后通过"accumulator"进行综合,每次上报事件"(rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_MT_REPORT) "代表一个触点信息的完结。

继续看 TouchInputMapper::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);
    }
}

这里又调用了三个process,这三个process分别对应三种类型的触摸设备事件:CursorButton、CursorScroll、TouchButton,设计理念与mapper一样,也是在各自的process中判断type,匹配才进行处理,加到"accumulator"中,如:

void CursorScrollAccumulator::process(const RawEvent* rawEvent) {
    if (rawEvent->type == EV_REL) {
        switch (rawEvent->scanCode) {
        case REL_WHEEL:
            mRelWheel = rawEvent->value;
            break;
        case REL_HWHEEL:
            mRelHWheel = rawEvent->value;
            break;
        }
    }
}

再看sync函数,sync意为同步,那这里应该是真正将数据上报的地方了:

void TouchInputMapper::sync(nsecs_t when) {
    // Sync button state.
    // 将 mCursorButtonAccumulator.process 和 mTouchButtonAccumulator.process
    // 中处理得到的最新状态获取并同步到 mCurrentButtonState上来
    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
            | mCursorButtonAccumulator.getButtonState();
 
    // Sync scroll state.
    // 将通过 mCursorScrollAccumulator.process处理得到的最新状态同步到
    // mCurrentRawVScroll和 mCurrentRawHScroll当中
    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
    mCursorScrollAccumulator.finishSync();
 
    // Sync touch state.
    // 同样, 将通过 mMultiTouchMotionAccumulator.process处理得到的多点触控数据
    // 同步(同步至成员变量 mCurrentRawPointerData中)
    bool havePointerIds = true;
    mCurrentRawPointerData.clear();
    syncTouch(when, &havePointerIds);
 
#if DEBUG_RAW_EVENTS
    if (!havePointerIds) {
        LOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
                mLastRawPointerData.pointerCount,
                mCurrentRawPointerData.pointerCount);
    } else {
        LOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
                "hovering ids 0x%08x -> 0x%08x",
                mLastRawPointerData.pointerCount,
                mCurrentRawPointerData.pointerCount,
                mLastRawPointerData.touchingIdBits.value,
                mCurrentRawPointerData.touchingIdBits.value,
                mLastRawPointerData.hoveringIdBits.value,
                mCurrentRawPointerData.hoveringIdBits.value);
    }
#endif
 
    // Reset state that we will compute below.
    mCurrentFingerIdBits.clear();
    mCurrentStylusIdBits.clear();
    mCurrentMouseIdBits.clear();
    mCurrentCookedPointerData.clear();
 
    if (mDeviceMode == DEVICE_MODE_DISABLED) { //disable mode, 丢弃
        // 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;
        //针对多点触摸事件, mLastRawPointerData无数据&&mCurrentRawPointerData中有数据, 意味着现在是首次按下
        bool initialDown = mLastRawPointerData.pointerCount == 0
                && mCurrentRawPointerData.pointerCount != 0;
        //针对触摸按键事件, mLastButtonState状态为空&&mCurrentButtonState状态不为空则认为按键动作为DOWN
        bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; 
        if (initialDown || buttonsPressed) {
            // If this is a touch screen, hide the pointer on an initial down.
            if (mDeviceMode == DEVICE_MODE_DIRECT) {
                getContext()->fadePointer();
            }
 
            // Initial downs on external touch devices should wake the device.
            // 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;
            }
        }
 
        // Synthesize key down from raw buttons if needed.
        // 根据 policyFlags, mLastButtonState和mCurrentButtonState等这些事件, 软件生成相应的
        // 按键事件, 然后通过 notyfyKey上报
        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
                policyFlags, mLastButtonState, mCurrentButtonState);
 
        // Consume raw off-screen touches before cooking pointer data.
        // If touches are consumed, subsequent code will not receive any pointer data.
        // 对 mCurrentRawPointerData进行判断, 如果是虚拟按键则生成对应按键并上报
        if (consumeRawTouches(when, policyFlags)) {
            // 返回 TRUE则表示为虚拟按键事件, 已经处理完毕, 清除 mCurrentRawPointerData
            mCurrentRawPointerData.clear();
        }
 
        // 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.
        // 呵呵, 这个函数名字取得很形象
        // 前面说过, 之前的数据是保存在 mCurrentRawPointerData当中, 数据是未处理的, 是raw
        // 而这里则是进行加工, cook, 比如pressure换算, x&y坐标翻转等, 结果存在 mCurrentCookedPointerData中
        // 即 mCurrentRawPointerData -> mCurrentCookedPointerData
        cookPointerData();
 
        // Dispatch the touches either directly or by translation through a pointer on screen.
        // 开始分发 mCurrentCookedPointerData
        // 如果设备模式为 DEVICE_MODE_POINTER, 则要先作一下 mapping, 即映射(是否类似于电脑触摸板???)
        if (mDeviceMode == DEVICE_MODE_POINTER) {
            // 转换设备类型标志位
            for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
                uint32_t id = idBits.clearFirstMarkedBit();
                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
                    mCurrentStylusIdBits.markBit(id);
                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
                    mCurrentFingerIdBits.markBit(id);
                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
                    mCurrentMouseIdBits.markBit(id);
                }
            }
            for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
                uint32_t id = idBits.clearFirstMarkedBit();
                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
                    mCurrentStylusIdBits.markBit(id);
                }
            }
 
            // Stylus takes precedence over all tools, then mouse, then finger.
            // 这里说了, Stylus优先级最高, 其次为mouse , 再为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;
            }
 
            // 终于开始dispatch了
            dispatchPointerUsage(when, policyFlags, pointerUsage);
        } 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);
        }
 
        // Synthesize key up from raw buttons if needed. - 作者已经说得很明白了
        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
                policyFlags, mLastButtonState, mCurrentButtonState);
    }
 
    // Copy current touch to last touch in preparation for the next cycle.
    mLastRawPointerData.copyFrom(mCurrentRawPointerData);
    mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
    mLastButtonState = mCurrentButtonState;
    mLastFingerIdBits = mCurrentFingerIdBits;
    mLastStylusIdBits = mCurrentStylusIdBits;
    mLastMouseIdBits = mCurrentMouseIdBits;
 
    // Clear some transient state.
    mCurrentRawVScroll = 0;
    mCurrentRawHScroll = 0;
}

上面在处理数据时有对数据进行判断,当判断触点处于虚拟按键区域时,会生成对应的key事件,我们这里再来看一下它是怎么做的:

bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
    // Check for release of a virtual key.
    // 虚拟按键当前为 DOWN状态
    if (mCurrentVirtualKey.down) {
        // 当前手指未按下任何区域
        if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
            // Pointer went up while virtual key was down.
            mCurrentVirtualKey.down = false;
            if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
                LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                        mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
                //制造一个 UP事件并上报
                dispatchVirtualKey(when, policyFlags,
                        AKEY_EVENT_ACTION_UP,
                        AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
            }
            return true;
        }
 
        if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
            uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
            const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
            const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
            //手指当前所触控区域仍然为 mCurrentVirtualKey所存储按键
            if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
                // Pointer is still within the space of the virtual key.
                return true;
            }
        }
 
        // Pointer left virtual key area or another pointer also went down.
        // Send key cancellation but do not consume the touch yet.
        // This is useful when the user swipes through from the virtual key area
        // into the main display surface.
        // 手指当前按下区域已经不是之前触控按键所在区域
        mCurrentVirtualKey.down = false;
        if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
            LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
                    mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
            //制造一个 UP事件并上报
            dispatchVirtualKey(when, policyFlags,
                    AKEY_EVENT_ACTION_UP,
                    AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
                            | AKEY_EVENT_FLAG_CANCELED);
        }
    }
 
    //判断是否符合DOWN事件特征
    if (mLastRawPointerData.touchingIdBits.isEmpty()
            && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
        // Pointer just went down.  Check for virtual key press or off-screen touches.
        uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
        const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
        if (!isPointInsideSurface(pointer.x, pointer.y)) {
            // If exactly one pointer went down, check for virtual key hit.
            // Otherwise we will drop the entire stroke.
            if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
                // 根据pointer坐标确定keyCode等
                const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
                if (virtualKey) {
                    mCurrentVirtualKey.down = true;
                    mCurrentVirtualKey.downTime = when;
                    mCurrentVirtualKey.keyCode = virtualKey->keyCode;
                    mCurrentVirtualKey.scanCode = virtualKey->scanCode;
                    mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey(
                            when, getDevice(), virtualKey->keyCode, virtualKey->scanCode);
 
                    if (!mCurrentVirtualKey.ignored) {
#if DEBUG_VIRTUAL_KEYS
                        LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
                                mCurrentVirtualKey.keyCode,
                                mCurrentVirtualKey.scanCode);
#endif
                        // 创造 DOWN事件并上报
                        dispatchVirtualKey(when, policyFlags,
                                AKEY_EVENT_ACTION_DOWN,
                                AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
                    }
                }
            }
            return true;
        }
    }
 
    // Disable all virtual key touches that happen within a short time interval of the
    // most recent touch within the screen area.  The idea is to filter out stray
    // virtual key presses when interacting with the touch screen.
    //
    // Problems we're trying to solve:
    //
    // 1. While scrolling a list or dragging the window shade, the user swipes down into a
    //    virtual key area that is implemented by a separate touch panel and accidentally
    //    triggers a virtual key.
    //
    // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
    //    area and accidentally triggers a virtual key.  This often happens when virtual keys
    //    are layed out below the screen near to where the on screen keyboard's space bar
    //    is displayed.
    // 在mConfig.virtualKeyQuietTime这个时间内禁止所有虚拟按键
    if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
        mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
    }
    return false;
}

通过sync函数,我们发现,touch所有事件的分发,根据 device mode的不同,都是通过以下两种方式完成的:

DEVICE_MODE_POINTER:

dispatchPointerUsage(when, policyFlags, pointerUsage);

DEVICE_MODE_DIRECT:

dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);

而上面这四个函数最终也都是通过调用 dispatchMotion,只是使用的参数(第四个参数, 即action)不一样罢了:

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)

这里贴出 dispatchTouches函数看一下:

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
    BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
    BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
    int32_t metaState = getContext()->getGlobalMetaState();
    int32_t buttonState = mCurrentButtonState;
 
    if (currentIdBits == lastIdBits) {
        if (!currentIdBits.isEmpty()) {
            // No pointer id changes so this is a move event.
            // 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 {
        // There may be pointers going up and pointers going down and pointers moving
        // all at the same time.
        BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
        BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
        BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
        BitSet32 dispatchedIdBits(lastIdBits.value);
 
        // Update last coordinates of pointers that have moved so that we observe the new
        // pointer positions at the same time as other pointers that have just gone up.
        bool moveNeeded = updateMovedPointers(
                mCurrentCookedPointerData.pointerProperties,
                mCurrentCookedPointerData.pointerCoords,
                mCurrentCookedPointerData.idToIndex,
                mLastCookedPointerData.pointerProperties,
                mLastCookedPointerData.pointerCoords,
                mLastCookedPointerData.idToIndex,
                moveIdBits);
        if (buttonState != mLastButtonState) {
            moveNeeded = true;
        }
 
        // Dispatch pointer up events.
        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) {
            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,
                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
                    mCurrentCookedPointerData.pointerProperties,
                    mCurrentCookedPointerData.pointerCoords,
                    mCurrentCookedPointerData.idToIndex,
                    dispatchedIdBits, downId,
                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }
    }
}

可以发现其action用到了 AMOTION_EVENT_ACTION_MOVE 和 AMOTION_EVENT_ACTION_POINTER_UP,所有的action包含以下几种:

enum {
    AMOTION_EVENT_ACTION_MASK = 0xff,
    AMOTION_EVENT_ACTION_POINTER_INDEX_MASK  = 0xff00,
    AMOTION_EVENT_ACTION_DOWN = 0,
    AMOTION_EVENT_ACTION_UP = 1,
    AMOTION_EVENT_ACTION_MOVE = 2,
    AMOTION_EVENT_ACTION_CANCEL = 3,
    AMOTION_EVENT_ACTION_OUTSIDE = 4,
    AMOTION_EVENT_ACTION_POINTER_DOWN = 5,
    AMOTION_EVENT_ACTION_POINTER_UP = 6,
    AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
    AMOTION_EVENT_ACTION_SCROLL = 8,
    AMOTION_EVENT_ACTION_HOVER_ENTER = 9,
    AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
};

进入 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) {
    PointerCoords pointerCoords[MAX_POINTERS];
    PointerProperties pointerProperties[MAX_POINTERS];
    uint32_t pointerCount = 0;
    while (!idBits.isEmpty()) {
        uint32_t id = idBits.clearFirstMarkedBit();
        uint32_t index = idToIndex[id];
        pointerProperties[pointerCount].copyFrom(properties[index]);
        pointerCoords[pointerCount].copyFrom(coords[index]);
 
        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }
 
        pointerCount += 1;
    }
 
    LOG_ASSERT(pointerCount != 0);
 
    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            action = AMOTION_EVENT_ACTION_UP;
        } else {
            // Can't happen.
            LOG_ASSERT(false);
        }
    }
 
    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, flags, metaState, buttonState, edgeFlags,
            pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}

发现最终是调用 getListener()->notifyMotion(&args),继续看代码(确实有点累了):

getListener()获取的是 mQueuedListener:

InputListenerInterface* InputReader::ContextImpl::getListener() {
    return mReader->mQueuedListener.get();
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
    mArgsQueue.push(new NotifyMotionArgs(*args));
}

哦,原来只是用参数构建 NotifyMotionArgs对象加入队列。

看到这里,相信很多人都会有疑问,事件只是经过一系列处理、转换后存到了mArgsQueue中,还是没有上报上去啊!?上报的动作到底在哪里呢?

我们再回过头来看一下 InputReader::loopOnce这个函数:

void InputReader::loopOnce() {
    int32_t timeoutMillis;
    { // acquire lock
        AutoMutex _l(mLock);
 
        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            refreshConfigurationLocked(changes);
        }
 
        timeoutMillis = -1;
        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock
 
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
 
    { // acquire lock
        AutoMutex _l(mLock);
 
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
        if (!count || timeoutMillis == 0) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
#if DEBUG_RAW_EVENTS
            LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
            mNextTimeout = LLONG_MAX;
            timeoutExpiredLocked(now);
        }
    } // release lock
 
    // Flush queued events out to the 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();
}

我们这一节的分析都集中在 mEventHub->getEvents 和 processEventsLocked当中,但在最后它还调用了一个函数 flush(),一看到这个函数大家应该马上会想到写文件时的flush吧!——即所有真正的磁盘写动作都是在flush时完成的!那这里是不是类似呢?

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();
}

继续看一下 NotifyArgs这个类:

/* Superclass of all input event argument objects */
struct NotifyArgs {
    virtual ~NotifyArgs() { }
 
    virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
};

可以发现这是一个无法实例化的父类,因为其 notify函数是纯虚函数,我们再看一下它有多少子类:

struct NotifyConfigurationChangedArgs : public NotifyArgs 
struct NotifyKeyArgs : public NotifyArgs
struct NotifyMotionArgs : public NotifyArgs
struct NotifySwitchArgs : public NotifyArgs 
struct NotifyDeviceResetArgs : public NotifyArgs

在上面所示的 dispatchMotion函数中可以看到,触屏事件分发时所用的 NotifyArgs子类为 NotifyMotionArgs:

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyMotion(this);
}

这个listener是何方神圣?

首先看到是这里传入的:

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();
}

而这个成员变量 mInnerListener又是在构建函数中传入的:

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);
 
    { // acquire lock
         ...
}

listener这个参数还是传进来的,必须再找到 InputReader构建的地方:

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();
}

一切都明白了!原来这个listener就是 InputDispatcher的对象 mDispatcher!

我们来看一下 interceptMotionBeforeQueueing这个函数,直接从名字上看,应该是说在将motion事件加入队列前进行拦截

void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
    // Policy:
    // - Ignore untrusted events and pass them along.
    // - No special filtering for injected events required at this time.
    // - Filter normal events based on screen state.
    // - For normal events brighten (but do not wake) the screen if currently dim.
    if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
        if (isScreenOn()) {
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
 
            if (!isScreenBright()) {
                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
            }
        } else {
            JNIEnv* env = jniEnv();
            // 由register_android_server_InputManager可知,这里实际调用的是
            // com/android/server/wm/InputManager类中的 interceptMotionBeforeQueueingWhenScreenOff函数
            jint wmActions = env->CallIntMethod(mCallbacksObj,
                        gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
                        policyFlags);
            if (checkAndClearExceptionFromCallback(env,
                    "interceptMotionBeforeQueueingWhenScreenOff")) {
                wmActions = 0;
            }
 
            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
            // 根据 interceptMotionBeforeQueueingWhenScreenOff返回的wmAction进行处理
            handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
        }
    } else {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    }
}

那这个 gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff到底最终调用的是哪个函数呢?

InputManager.java

        @SuppressWarnings("unused")
        public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
            return mWindowManagerService.mInputMonitor.interceptMotionBeforeQueueingWhenScreenOff(
                    policyFlags);
        }

继续:

InputMonitor.java

    /* Provides an opportunity for the window manager policy to intercept early
     * motion event processing when the screen is off since these events are normally
     * dropped. */
    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
    }

找到了:

PhoneWindowManager.java

    /** {@inheritDoc} */
    @Override
    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
        int result = 0;
 
        final boolean isWakeMotion = (policyFlags
                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
        if (isWakeMotion) {
            // 如果当前界面为锁屏界面
            if (mKeyguardMediator.isShowing()) {
                // If the keyguard is showing, let it decide what to do with the wake motion.
                // 让锁屏进行一些处理
                mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
            } else {
                // Otherwise, wake the device ourselves.
                // 设置标志 ACTION_POKE_USER_ACTIVITY
                result |= ACTION_POKE_USER_ACTIVITY;
            }
        }
        return result;
    }


void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        LOGD("handleInterceptActions: Going to sleep.");
#endif
        //调用 PowerManagerService::goToSleep
        android_server_PowerManagerService_goToSleep(when);
    }
 
    if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        LOGD("handleInterceptActions: Poking user activity.");
#endif
        //调用 PowerManagerService::userActivity
        android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
    }
 
    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    } else {
#if DEBUG_INPUT_DISPATCHER_POLICY
        LOGD("handleInterceptActions: Not passing key to user.");
#endif
    }
}

四、笔记

updateInputWindowsLw -> setInputWindows -> nativeSetInputWindows -> setInputWindows -> 
mInputManager->getDispatcher()->setInputWindows(windowHandles) -> 更新 mFocusedWindowHandle 
 
 
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
=>更新 mMonitoringChannels
 
 
//InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    ...
 
    // Handle case where the policy asked us to try again later last time.
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
        if (currentTime < entry->interceptKeyWakeupTime) {
            if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
                *nextWakeupTime = entry->interceptKeyWakeupTime;
            }
            return false; // wait until next wakeup
        }
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
        entry->interceptKeyWakeupTime = 0;
    }
 
    // Give the policy a chance to intercept the key.
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); //interceptKeyBeforeDispatching
            if (mFocusedWindowHandle != NULL) {
                commandEntry->inputWindowHandle = mFocusedWindowHandle;
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
            return false; // wait for the command to run
        } else {
            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
        }
    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
        if (*dropReason == DROP_REASON_NOT_DROPPED) {
            *dropReason = DROP_REASON_POLICY;
        }
    }
 
    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }
 
    // Identify targets.
    Vector<InputTarget> inputTargets;
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime); //将 mFocusedWindowHandle 加入 inputTargets
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }
 
    setInjectionResultLocked(entry, injectionResult);
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        return true;
    }
 
    addMonitoringTargetsLocked(inputTargets); //将 mMonitoringChannels 加入 inputTargets
 
    // Dispatch the key.
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}