1. SystemServer.java 启动了InputManagerService和WindowManagerService.java

frameworks/base/services/java/com/android/server/SystemServer.java

            Slog.i(TAG, "Input Manager");            inputManager = new InputManagerService(context, wmHandler);            Slog.i(TAG, "Window Manager");            wm = WindowManagerService.main(context, power, display, inputManager,                    uiHandler, wmHandler,                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,                    !firstBoot, onlyCore);            ServiceManager.addService(Context.WINDOW_SERVICE, wm);            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);     
            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());      inputManager.start();

2. InputManagerService 调用NativeInit启动jni方法,返回InputManager.cpp的指针给mPtr.

    public InputManagerService(Context context, Handler handler) {        this.mContext = context;        this.mHandler = new InputManagerHandler(handler.getLooper());        mUseDevInputEventForAudioJack =                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());    }

3. JNI创建了一个EventHub和InputManager. 这里只要是创建了一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。注意,这里的 InputManager类是定义在C++层的,和前面在Java层的InputManager不一样,不过它们是对应关系。EventHub类是真正执 行监控键盘事件操作的地方.

frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobject contextObj,        jobject serviceObj, const sp<Looper>& looper) :        mLooper(looper) {    JNIEnv* env = jniEnv();    mContextObj = env->NewGlobalRef(contextObj);    mServiceObj = env->NewGlobalRef(serviceObj);    ...    sp<EventHub> eventHub = new EventHub();    mInputManager = new InputManager(eventHub, this, this);}


4. InputManager创建了一个InputDispatcher对象和一个InputReader对象,并且分别保存在成员变量mDispatcher 和mReader中。InputDispatcher类是负责把键盘消息分发给当前激活的Activity窗口的,而InputReader类则是通过 EventHub类来实现读取键盘事件的.

frameworks/base/services/input/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);    initialize();}void InputManager::initialize() {    mReaderThread = new InputReaderThread(mReader);    mDispatcherThread = new InputDispatcherThread(mDispatcher);}


5. InputManager.start()函数是在第一步SystemServer中,创建完WMS实例后调用的。start()启动InputReaderThread & InputDispatherThread.

这个函数主要就是分别启动一个InputDispatcherThread线程和一个InputReaderThread线程来读取和分发键 盘消息的了。这里的InputDispatcherThread线程对象mDispatcherThread和InputReaderThread线程对 象是在前面创建的,调用了它们的run函数后,就会进入到它们的threadLoop函数中去,只要threadLoop函数返回true,函数 threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用。

status_t InputManager::start() {    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);    ....    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);     ....    return OK;}  

6. InputDispatcherThread

bool InputDispatcherThread::threadLoop() {    mDispatcher->dispatchOnce();    return true;}
这个函数很简单,把键盘消息交给dispatchOnceInnerLocked函数来处理,这个过程我们在后面再详细分析,然后调用 mLooper->pollOnce函数等待下一次键盘事件的发生。
void InputDispatcher::dispatchOnce() {    nsecs_t nextWakeupTime = LONG_LONG_MAX;    { // acquire lock        AutoMutex _l(mLock);        mDispatcherIsAliveCondition.broadcast();        // Run a dispatch loop if there are no pending commands.        // The dispatch loop might enqueue commands to run afterwards.        if (!haveCommandsLocked()) {            dispatchOnceInnerLocked(&nextWakeupTime);        }        // Run all pending commands if there are any.        // If any commands were run then force the next poll to wake up immediately.        if (runCommandsLockedInterruptible()) {            nextWakeupTime = LONG_LONG_MIN;        }    } // 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);}

我们接着分析InputReader类读取键盘事件的过程s。在调用了InputReaderThread线程类的run就函数后,同样会进入到 InputReaderThread线程类的threadLoop函数中去。这里通过成员函数mEventHub来负责键盘消息的读取工作,如果当前有键盘事件发生或者有键盘事件等待处理,通过mEventHub的 getEvent函数就可以得到这个事件,然后交给 processEventsLocked 函数进行处理,这个函数主要就是唤醒前面的InputDispatcherThread 线程,通知它有新的键盘事件发生了,它需要进行一次键盘消息的分发操作了,这个函数我们后面再进一步详细分析;如果没有键盘事件发生或者没有键盘事件等待 处理,那么调用mEventHub的getEvent函数时就会进入等待状态。

void InputReader::loopOnce() {    int32_t oldGeneration;    int32_t timeoutMillis;    bool inputDevicesChanged = false;    Vector<InputDeviceInfo> inputDevices;    { // acquire lock        AutoMutex _l(mLock);    ....    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);    { // acquire lock        AutoMutex _l(mLock);        mReaderIsAliveCondition.broadcast();        if (count) {            processEventsLocked(mEventBuffer, count);        }        ....        if (oldGeneration != mGeneration) {            inputDevicesChanged = true;            getInputDevicesLocked(inputDevices);        }    } // release lock    // Send out a message that the describes the changed input devices.    if (inputDevicesChanged) {        mPolicy->notifyInputDevicesChanged(inputDevices);    }    // 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();}


7. E ventHub.getEvents 这个函数定义在frameworks/base/libs/ui/EventHub.cpp文件中:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {    ALOG_ASSERT(bufferSize >= 1);    AutoMutex _l(mLock);    struct input_event readBuffer[bufferSize];    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;            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; ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } if (mNeedToScanDevices) { mNeedToScanDevices = false;
//这个函数主要就是调用openDevice函数来分别打开/dev/input/event0、/dev/input/mice和/dev/input/mouse0三个设备文件了            scanDevicesLocked();            mNeedToSendFinishedDeviceScan = true;        }//接着,检查当前是否有新的输入设备加入进来:        while (mOpeningDevices != NULL) {            Device* device = mOpeningDevices;            ALOGV("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;            event += 1;            if (--capacity == 0) {                break;            }        }//最后,就是要检查当前是否有还未处理的输入设备事件发生了:        // Grab the next input event.        bool deviceChanged = false;        while (mPendingEventIndex < mPendingEventCount) {            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {                if (eventItem.events & EPOLLIN) {                    mPendingINotify = true;                } else {                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);                }                continue;            }            if (eventItem.data.u32 == EPOLL_ID_WAKE) {                if (eventItem.events & EPOLLIN) {                    ALOGV("awoken after wake()");                    awoken = true;                    char buffer[16];                    ssize_t nRead;                    do {
//等待在wait at epoll                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));                } else {                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",                            eventItem.events);                }                continue;            }            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);            if (deviceIndex < 0) {                ALOGW("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,                        sizeof(struct input_event) * capacity);                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {                。。。。                } 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];                        ALOGV("%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);                        event->when = now;                        event->deviceId = deviceId;                        event->type = iev.type;                        event->code = iev.code;                        event->value = iev.value;                        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 if (eventItem.events & EPOLLHUP) {
            。。。。            }        }        // 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) {            mPendingINotify = false;            readNotifyLocked();            deviceChanged = true;        }        // Report added or removed devices immediately.        if (deviceChanged) {            continue;        }        // 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);        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) {                ALOGW("poll failed (errno=%d)\n", errno);                usleep(100000);            }        } else {            // Some events occurred.            mPendingEventCount = size_t(pollResult);        }    }    // All done, return the number of events we read.    return event - buffer;}




更多相关文章

  1. C语言函数以及函数的使用
  2. Android 隐藏显示键盘
  3. Android中回调下载事件处理实现步骤
  4. Android软键盘softboard(1)
  5. Android 设置DrawableRight和DrawableLeft 点击事件
  6. Android touch事件一种解释
  7. Android Touch事件传递机制引发的血案
  8. Phonegap软键盘遮挡输入框问题

随机推荐

  1. android 上传文件到服务器代码实例
  2. 一份关于 Java、Kotlin 与 Android(安卓)
  3. android 搭建开发环境
  4. 移动3g为什么这么坑爹
  5. 二、Android(安卓)NDK编程预备之Java jni
  6. ListView 使用详解
  7. android Service与BroadcastReceiver
  8. android 电话状态的监听(来电和去电)
  9. Android保存图片到系统相册并更新
  10. android中的mvp模式(二)