Android系统源码阅读(11):Android的InputManagerService的工作过程

请对照AOSP版本:6.0.1_r50。

1. 创建InputManager

这里和老罗当年的版本有很大不同了,有了InputManagerService管理InputManager。

1.1

想要探索如何启动的相关server,需要从SystemServer开始探寻。从SystemServer的进程开始运行开始,它就会创建一些系统server,这里就会启动other services。

其中,会创建Input Manager和Window Manager两个服务。

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

Slog.i(TAG, "Input Manager");inputManager = new InputManagerService(context);Slog.i(TAG, "Window Manager");wm = WindowManagerService.main(context, inputManager,        mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,        !mFirstBoot, mOnlyCore);ServiceManager.addService(Context.WINDOW_SERVICE, wm);ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//..inputManager.start();

1.2

先来仔细端详一下InputManagerService的构造函数。这里会调用c++层的初始化函数。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java :

this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper);//..mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

注意这里将DisplayThread的Looper传递过去,DisplayThread是一个单例模式的类,它会启动唯一的线程。同时DisplayThread是一个HandlerThread的子类,实现了Looper循环机制。DisplayThread是用来执行和显示有关的操作,显示操作一般需要比较小的延迟。DisplayThread只能被WindowManager、DisplayManager,InputManager用来执行一些快速地实时操作。

1.3

这一步首先将java层的MessageQueue变为了c++的MessageQueue。然后构造了一个NativeInputManager对象,最后将指向该对象的指针im返回给java层。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp :

NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper());

1.4

在构造NativeInputManager时,会创建一个InputManager对象mInputManager。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp :

sp<EventHub> eventHub = new EventHub();mInputManager = new InputManager(eventHub, this, this);

1.5

这一步会创建一个dispatcher负责分发输入事件,一个reader负责获取事件。
frameworks/native/services/inputflinger/InputManager.cpp :

mDispatcher = new InputDispatcher(dispatcherPolicy);mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();

1.6

这里会创建两个线程,在以后的步骤中会用来运行前面创建的dispathcer和reader。

frameworks/native/services/inputflinger/InputManager.cpp :

mReaderThread = new InputReaderThread(mReader);mDispatcherThread = new InputDispatcherThread(mDispatcher);

2. 启动InputManager

将视线再次回到SystemServer中,在创建完InputManagerService后,需要将这个Service启动,同样是在1.1的startOtherServices函数里,调用了InputManagerService的成员函数start。

2.1

这里首先调用了c++层的nativeStart,然后InputManagerService将自己交给Watchdog监视。然后注册了PointerSpeedSetting和ShowTouchesSetting两个Observer。

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java :

nativeStart(mPtr);// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);registerPointerSpeedSettingObserver();registerShowTouchesSettingObserver();

这两个Observer暂时还没搞清楚是干什么的。

2.2

这一步将传来的ptr参数转化为一个NativeInputManager指针,同时开始启动NativeInputManager中的InputManager。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp :

NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);status_t result = im->getInputManager()->start();

2.3

这里会启动在1.6中创建的两个线程,分别用来分发和监听Input事件。

frameworks/native/services/inputflinger/InputManager.cpp :

status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);)

3. 启动InputDispatcher

在2.3中运行的线程以threadLoop为入口,开始进入循环。

3.1

这一步直接将任务交给InputDispatcher的dispatchOnce函数。

frameworks/native/services/inputflinger/InputDispatcher.cpp :

bool InputDispatcherThread::threadLoop() {    mDispatcher->dispatchOnce();    return true;}

3.2

整个函数如下:

frameworks/native/services/inputflinger/InputDispatcher.cpp :

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    nsecs_t currentTime = now();    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);    mLooper->pollOnce(timeoutMillis);}

在这一步骤中,首先判断是否有Command还未被执行,如果有去执行Command。否则,调用dispatchOnceInnerLocked函数去获取事件,这里会将nextWakeupTime传递过去,让其设置合适的苏醒时间,具体内容在以后讲解。然后runCommandsLockedInterruptible函数会执行缓存的Command,如果有Command在这一步中被执行,则需要将苏醒事件设置为LONG_LONG_MIN,因为执行这些命令需要耗费事件,在这期间可能已经有输入事件发生了,所有下次循环不需要等待。

最后,根据等待时间和当前时间,计算出需要睡眠的时间,通过pollOnce进入睡眠,等待唤醒,或者超时。

3.3

这里和上一个章节中的pollOnce道理相同。

3.4

这里会调用epoll_wait函数,使其在mEpollFd所描述的epoll上等待一段时间,这个epoll监听着文件描述符的读写事件。如果有人在pip中写入,则会返回,否则等待指定时间后返回。

system/core/libutils/Looper.cpp

int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

4. 启动InputReader

在2.3中运行的线程以threadLoop为入口,开始进入循环。

4.1

这一步与3.1一样,将任务丢给InputReader处理。

4.2

这一步会尝试从mEventHub中获取事件,如果获取一些事件,则进行处理。
frameworks/native/services/inputflinger/InputReader.cpp :

//从EventHub中获取event,这里先详细讲解这一步size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//省略..if (count) {    //事件处理,将在后面博客中讲解    processEventsLocked(mEventBuffer, count);}

这里我们先考虑如何从EventHub中获取事件的。

4.3

首先这一个函数不是就获得一个event这么简单,它是想获得一组event,这里和旧版本有所不同,可见工程师对系统做了优化。这一步内容比较到,让我们通过注释来讲解。

frameworks/native/services/inputflinger/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];    //event 指向了存储事件的位置    RawEvent* event = buffer;    size_t capacity = bufferSize;    bool awoken = false;    //开始循环获取事件,目的是填充buffer    for (;;) {        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);        // Reopen input devices if needed.        //如果需要重新打开输入设备,则首先要关闭所有的设备        if (mNeedToReopenDevices) {            mNeedToReopenDevices = false;            ALOGI("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;            ALOGV("Reporting device closed: id=%d, name=%s\n",                 device->id, device->path.string());            mClosingDevices = device->next;            //创建了一个设备removed的event            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;            //下面会详细讲解这里如何获取输入设备的            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            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;            }        }    //以上步骤主要是负责重新获取接入的设备,下面将会负责获得设备中的event        // Grab the next input event.        bool deviceChanged = false;        //开始循环获取pending的event        //当前处理的Event序号是否小于正在等待的事件数目,这里会循环读出所有等待的事件        while (mPendingEventIndex < mPendingEventCount) {        //获取一个event项            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];        //如果这是个INotify事件            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;            }        //如果这是一个Id wake事件,则读出mWakeReadPipeFd的数据,让等待在这个文件描述符上的线程得到唤醒             if (eventItem.data.u32 == EPOLL_ID_WAKE) {                if (eventItem.events & EPOLLIN) {                    ALOGV("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 {                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",                            eventItem.events);                }                continue;            }        //这里开始处理其它非特殊的event        //获取event项对应的设备的编号            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;            }            //获取设备,所有已知的设备都放在了mDevices中            Device* device = mDevices.valueAt(deviceIndex);            if (eventItem.events & EPOLLIN) {                //从这个设备中读出数据流,并且存入readBuffer下                int32_t readSize = read(device->fd, readBuffer,                        sizeof(struct input_event) * capacity);                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {                    // Device was removed before INotify noticed.                //先处理一些异常情况,先省略                //...                } else {                     //键盘事件的id需要特殊处理,一直设置为0                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;                    size_t count = size_t(readSize) / sizeof(struct input_event);                    //开始循环,从设备中读出每一个event                    for (size_t i = 0; i < count; i++) {                        struct input_event& iev = readBuffer[i];                        //这里做了许多处理事件异常时间的工作,先略过                        //...                        //将获取的事件存入event                        event->deviceId = deviceId;                        event->type = iev.type;                        event->code = iev.code;                        event->value = iev.value;                        //event指向下一个位置,容量也随之减少一个                        event += 1;                        capacity -= 1;                    }                    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.                        //buffer已经填满,退出处理pending event的循环,将index回到上一个位置,因为该设备event还没读完,下次再接着读                        mPendingEventIndex -= 1;                        break;                    }                }            } else if (eventItem.events & EPOLLHUP) {              //处理一些其它情况,省略              //...            }        }        //在读出所有event后,才能关闭设备,这里省略了对此的处理过程        //...        //到这里说明pending event已经处理完,或者buffer已经塞满。buffer塞满或者存了一些事件,则退出最外层填充buffer的循环        // Return now if we have collected any events or if we were explicitly awoken.        if (event != buffer || awoken) {            break;        }        //这里处理了一些wake lock的事情,省略        //...        //到这一步说明buffer里没有填任何事件,同时也没有pending event        //所以需要等待有人向device文件描述符里写入一些事件        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);        //时间已到,还是没有事件,那咱就结束吧        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);            //获取了一些event,那么继续循环,填充buffer!        }    }    // All done, return the number of events we read.    return event - buffer;}

4.4

从这里开始扫描设备。在研究这个函数前,先看一下DEVICE_PATH的来头:

frameworks/native/services/inputflinger/EventHub.cpp :

   //这一段代码位于EventHub的构造函数中,这里使用了linux的inotify机制   //inotify机制可以监控文件的变化   //因此系统可以实时监控设备的添加和移除   mINotifyFd = inotify_init();   int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

frameworks/native/services/inputflinger/EventHub.cpp :

void EventHub::scanDevicesLocked() {     //扫描目录:/dev/input    status_t res = scanDirLocked(DEVICE_PATH);    if(res < 0) {        ALOGE("scan dir failed for %s\n", DEVICE_PATH);    }    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {        //创建一个虚拟键盘        createVirtualKeyboardLocked();    }}

4.5

这里开始扫描/dev/input/目录下的所有设备。

frameworks/native/services/inputflinger/EventHub.cpp :

status_t EventHub::scanDirLocked(const char *dirname){    char devname[PATH_MAX];    char *filename;    DIR *dir;    struct dirent *de;    dir = opendir(dirname);    if(dir == NULL)        return -1;    strcpy(devname, dirname);    filename = devname + strlen(devname);    //filename指向了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);        //打开设备,devname里是设备的绝对路径        openDeviceLocked(devname);    }    closedir(dir);    return 0;}

4.6

frameworks/native/services/inputflinger/EventHub.cpp :

status_t EventHub::openDeviceLocked(const char *devicePath) {    char buffer[80];    //打开文件    int fd = open(devicePath, O_RDWR | O_CLOEXEC);    if(fd < 0) {        ALOGE("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    //删除排除的设备    //一下步骤从文件中获取device的基本信息    //...    // Get device driver version.    // Get device identifier.    // Get device physical location.    // Get device unique id.    // Fill in the descriptor.    // Make file descriptor non-blocking for use with poll().    //创建device对象    // 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);    //根据device的特征,设置device的class参数    //...    // Register with epoll.    struct epoll_event eventItem;    memset(&eventItem, 0, sizeof(eventItem));    eventItem.events = EPOLLIN;    if (mUsingEpollWakeup) {        eventItem.events |= EPOLLWAKEUP;    }    eventItem.data.u32 = deviceId;    //将该device的文件fd交给epoll监视,以及时获得它的变化    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {        ALOGE("Could not add device fd to epoll instance. errno=%d", errno);        delete device;        return -1;    }    //处理时钟问题..    //添加device    addDeviceLocked(device);    return 0;

4.7

这一步比较轻松,将创建好的device对象放入mDevices即可。

void EventHub::addDeviceLocked(Device* device) {    mDevices.add(device->id, device);    device->next = mOpeningDevices;    mOpeningDevices = device;}

更多相关文章

  1. python获取android设备的GPS信息脚本分享
  2. Android中点击事件的四种写法
  3. Android 拦截返回键事件的实例详解
  4. adb 发送文件到Android设备和从Android手机复制文件
  5. Android获得所有存储设备位置最佳方式
  6. android输入子设备类型
  7. android Home事件汇总
  8. 【Android Developers Training】 10. 序言:支持不同设备
  9. Android事件模型

随机推荐

  1. Android 之 手机全屏显示
  2. Android 实现多个Audio文件的顺序播放
  3. Android(安卓)下网络状态监听
  4. android之layout(二)RelativeLayout, Table
  5. android启动之init进程详解
  6. Android实现从activity中停止Service的方
  7. Android:配置LitePal 3.0
  8. linux中android真机调试配置
  9. android打电话
  10. Android:监听应用前后台切换及思考