android4.4电源管理——Input系统(Power键处理)

在开始叙述各部分的功能之前,我们还是先说说更个Input系统的来龙去脉,一方面能够知道Input系统从哪儿来,另一方面能对整个系统有个大概的了解,使我们不至于迷失在浩瀚的Android源码中。在Android系统中一说到重要的服务,基本都是要从systemserver进程开始说起,因为他是Android世界的开拓者,创建了Android世界所需要个基础。同样,Input系统也是从systemserver中开始说起,首先创建一个InputManagerService对象,为这个对象设置与WindowManagerService相关的回调函数,然后调用InputManagerService的start函数。

SystemServer.java

    public void initAndLoop() {

            Slog.i(TAG, "Power Manager");
            power = new PowerManagerService();

            Slog.i(TAG, "Display Manager");
            display = new DisplayManagerService(context, wmHandler);

            Slog.i(TAG, "Input Manager");
            inputManager = new InputManagerService(context, wmHandler);//阶段一,初始化输入服务

            wm = WindowManagerService.main(context, power, display, inputManager,
                    wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                    !firstBoot, onlyCore);

            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

            ActivityManagerService.self().setWindowManager(wm);

            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            inputManager.start();//阶段二、启动输入服务

            display.setWindowManager(wm);
            display.setInputManager(inputManager);

    }

阶段一、InputManager的初始化

WindowManagerService.java

    public static WindowManagerService main(final Context context,
            final PowerManagerService pm, final DisplayManagerService dm,
            final InputManagerService im, final Handler wmHandler,
            final boolean haveInputMethods, final boolean showBootMsgs,
            final boolean onlyCore) {
        final WindowManagerService[] holder = new WindowManagerService[1];
        wmHandler.runWithScissors(new Runnable() {
            @Override
            public void run() {
                holder[0] = new WindowManagerService(context, pm, dm, im,
                        haveInputMethods, showBootMsgs, onlyCore);
            }
        }, 0);
        return holder[0];
    }

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

        mInputManager = inputManager; // Must be before createDisplayContentLocked.
        mDisplayManagerService = displayManager;

    }

InputManagerService.java

    public InputManagerService(Context context, Handler handler) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(handler.getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//通过JNI调用来启动native层的input系统,然后把返回值存放在mPtr中
    }

从代码可以看出,InputManagerService的构造是很简单的,只是在最后通过JNI方法初始化了native层的Input系统。接下来我们就看看在native层都做了些什么,代码如下:

com_android_server_input_InputManagerService.cp

   在这里,重点关注nativeInit,进入C++层

static JNINativeMethod gInputManagerMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit",
            "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)I",
            (void*) nativeInit },
    { "nativeStart", "(I)V",
            (void*) nativeStart },

………..

    }

在这里,分析android_server_InputManager_nativeInit函数.

static jint nativeInit(JNIEnv* env, jclass clazz,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);// sp: Looper类强指针
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
//这里实例化了NativeInputManagerService的一个对象,使用的Java层的MessageQueue的Looper,意味着Java层消息和Native消息是在同一个MessageQueue中的
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,

            messageQueue->getLooper());

    im->incStrong(0);

    return reinterpret_cast(im); //把新建的NativeInputManager强制转换,返回给Java层 
}

在native层初始化的时候,创建了一个名叫NativeInputMnager的对象,这个对象是很重要的,因为它主要负责和系统的其他模块交互,而且InputReader和InputDispatcher都是只运行在Native层中,如果需要调用Java函数也是通过这个对象进行的,另外他实现了InputReaderPolicyInterface和InputDispatcherPolicyInterface,是一个重要的Policy。

NativeInputManager在构造过程中,完成了InputManager在native基本运行组件的创建:

1、创建了EventHub对象,它是事件的Android系统的起源地,所有的事件都是它从驱动中读取出来的;

2、创建了InputReaderThread线程用来执行InputReader的功能;InputDispatcherThread用来执行InputDispatcher的功能;

3、创建了InputManager来管理EventHub,InputReader,InputReaderThread,InputDispatcher,InputDispatcherThread这些Native运行的基本对象。

这些对象的创建过程中并没有非常重要的调用,这里略过代码。不过要注意一点的是NativeInputManager是InputReaderPolicyInterface和InputDispatcherPolicyInterface的子类,

因此在构造InputReader和InputDispatcher的时候要用到NativieInputManager对象。

  在对象构建完成后,开始执行start方法,让之前创建的这些对象运行起来。start方法也是比较简单的,就是通过JNI调用让native层的Input系统运行起来,然后在Java层把自己列入WatchDog的监视范围内。

之后定义下自己需要接受的外部通知等。那么到这里位置,整个Input系统就运行起来了,至于其中具体的功能我们再逐步分析。这部分内容叙述完毕。

com_android_server_input_InputManagerService.cpp

重点关注NativeInputManager类构造函数:

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp& looper) :
        mLooper(looper) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }

    sp eventHub = new EventHub();//new一个EventHub对象
    mInputManager = new InputManager(eventHub, this, this); //创建InputManager对象
}

这个函数创建一个EventHub对象,然后把它作为参数来创建InputManager对象。特别注意,InputManager是在C++里,具体在InputManager.cpp里。EventHub类在EventHub.cpp里,这个类和input事件获取有关。

InputManager.cpp

InputManager::InputManager(
        const sp& eventHub,
        const sp& readerPolicy,
        const sp& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

    initialize();
}

它创建了InputDispatcher对象,同时也创建了InputReader对象。并分别暂存于mDispatcher和mReader变量中。注意eventHub和mDispatcher都作为参数创建InputReader对象。

后面还用initialize来初始化。下面是initialize函数的定义:

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

它创建两个线程:

1、InputReaderThread线程,负责input事件的获取;

2、nputDispatcherThread线程,负责input消息的发送。

阶段二、InputManager的启动

开始InputManager.java的mInputManager.start()这个start方法。看究竟怎么启动。

InputManagerService.java

    public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);//调用本地方法nativeStart

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);

        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();

        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
    }

com_android_server_input_InputManagerService.cpp

static JNINativeMethod gInputManagerMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit",
            "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)I",
            (void*) nativeInit },
    { "nativeStart", "(I)V",
            (void*) nativeStart },

}

static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
    NativeInputManager* im = reinterpret_cast(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

先看getInputManager:

  inline sp getInputManager() const { return mInputManager; }//初始时构造mInputManager对象

InputManager.cpp

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

它主要是启动InputDispatcherThread和InputReaderThread这两个线程。前面提到了创建这两个线程。也创建了InputDispatcher和InputReader对象。下面就这两个对象做分解.

下面是class InputDispatcherThread : public Thread {

public:

    explicit InputDispatcherThread(const sp& dispatcher);

    ~InputDispatcherThread();

 

private:

    virtual bool threadLoop();

 

    sp mDispatcher;

};

由于它是Thread子类,于是继承它的run方法,进入run方法后会调用threadLoop(),在Thread类中它是虚函数,得由子类来复写,如下所示:

bool InputDispatcherThread::threadLoop() {

    mDispatcher->dispatchOnce();

    return true;

}

启动mDispatcher->dispatchOnce();

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

函数功能:dispatchOnceInnerLocked函数处理input输入消息,mLooper->pollOnce是等待下一次输入事件。

mLooper->pollOnce(timeoutMillis):

这个请看Looper.cpp文件中的Looper::pollOnce()函数。Looper里主要通过linux管道方式实现进程间通信,通过epoll机制实现外界事件请求作出响应。

接着,来分析InputReaderThread的启动。

在InputManagerService中start方法会通过JNI调用,启动Native层的InputReaderThread,InputDispatcherThread线程,从而开始Input系统的运行。InputReaderThread主要是执行和InputReader相关的内容,主要是从EventHub中读取事件,预处理事件,然会是根据policy来处理此事件,最后发送一个消息到InputDispatcher中通知事件的产生。紧接着InputDispatcher会开始事件的分发,通过InputChannel把事件分发给WindowManager或者应用程序。说以一个事件的流程是从 Eventhub  ---> InputReader  ---> InputDispatcher  ---> InputPublisher  ---> InputChannel  ---> InputConsumer  --->  WindowManager or Application.这就是整个事件分发的大致流程。

InputReader的功能,以及执行的流程  

从前面的内容我们可以知道,在InputManager的start方法被调用会,会执行两个线程,分别是InputReaderThread和InputDispatcherThread,虽然它们的启动在代码上有先后之分,但是在实际执行过程中是没有先后的,所以先从哪个线程开始解析Input系统不是很重要的。不过,我是按照从事件的产生到分发开始解析的,所以这里我是选择从InputReader开始。InputReader是Android系统中重要的部分,根据Android文档中的描述,主要功能就是:

(1) 从EventHub读取事件,这些事件是元事件,即没有经过加工或者仅仅是简单加工的处理的事件;

(2)把这些事件加工处理,生成inputEvent事件,这样封装之后的事件,可以满足Android系统的一些需求;

(3)把这些事件发送到事件监听器,即QueuedInputListener,这个监听器可以把事件传递给InputDispatcher。

下面我们就从线程开始执行的地方一步一步分析这些功能的实现。既然要看InputReader的功能,我就从InputReader的构造函数说起。前面在说到构造InputManager的时候,就创建了InputReader,当时没有介绍起功能和构造方法,我们从这里开始:

InputReader::InputReader(const sp& eventHub,
        const sp& policy,
        const sp& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);//在这里创建了一个QueuedInputListener,注意其参数是listener是InputDispatcher
    { // acquire lock
        AutoMutex _l(mLock);
        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

在InputReader创建的时候,这里把InputDispatcher作为参数传递进来,然后以InputDispatcher作为参数构造出了QueuedInputListener对象。所以现在有这么一个关系:InputReader持有一个QueuedInputListener,而QueuedInputListener持有InputDispatcher对象。

class InputReaderThread : public Thread {

public:

    InputReaderThread(const sp& reader);

    virtual ~InputReaderThread();

private:

    sp mReader;

    virtual bool threadLoop();//loop

};

在这里直接到InputReader.cpp文件

bool InputReaderThread::threadLoop() {

    mReader->loopOnce();

    return true;

}

往下走,在这里补充一点内容: Android系统在Native层中实现了一个类似于Java中的线程对象,即C++中的Thread类。这个线程类有个特点就是,当线程开始执行后,不一直重复执行threadLoop方法,知道这个线程的强引用计数变为零为止。所以,这里的threadLoop函数会不停地执行下去,也即是mReader->loopOnce()会循环执行下去,每循环一次就能从EventHub中读取出若干事件。下面我们就以一次循环过程为例,分析此线程的执行,loopOnce的代码如下:

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector inputDevices;
    ...
    //如果系统刚刚启动,或者有新的设备加入的话,timeoutMillis一般为0,意味着无需等待,可以立即返回;timeoutMillis一般为-1,意味着无限等待
     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//阶段一,通过EventHub的getEvents方法来获取input事件。

    {
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
             processEventsLocked(mEventBuffer, count);//阶段二,开始处理读取出来的元事件
        }

        ...
    }

    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    mQueuedListener->flush();//阶段三,把QueuedInputListener中的消息全部都开始处理

}

void QueuedInputListener::flush() {

    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);//mlnnerListener是InputDispatcher对象

        delete args;
    }
    mArgsQueue.clear();
}

这个函数主要包括三个阶段:

1、通过EventHub的getEvents方法来获取input事件。

2、从EventHub中读取出若干事件,然会对这些事件进行预处理。

3、把QueuedInputListener中的事件分发出去。

这个方法中包含了InputReader的主要功能,所以此线程每循环一次,都会执行完成一次InputReader的主要功能。接下来依次介绍着三个阶段:

阶段一,从EventHub获取事件

先简单介绍下EvenHub,这个类的主要功能就是主动监视Input驱动的变化,一旦有事件产生,就从产生事件相应的驱动中读取出这个事件。实现这个监视驱动功能,是通过Linux提供的epoll机制来实现。epoll机制简单地说就是高效地I/O多路复用机制,使用epoll_wait来监听所需要的文件描述符的变化,关于epoll的介绍有很多文章,man中也有详细的介绍。EventHub的主要功能是通过epoll_wait来实现的,所以EventHub所在的线程应该会阻塞在epoll_wait方法中,一直等到epoll_wait设置的超时时间。现在我们开始看看EventHub的实现,在EventHub的构造函数中,建立了一个管道,并把这个管道的读端和写端的文件描述符添加到epoll的监视之下,以便于其他的线程或者进程能够使EventHub所在的线程从epoll_wait的阻塞中返回。EventHub在创建完成之后,第一个被调用的方法就是getEvents,而且这个方法也是EventHub的主要功能,对于这个方法需要仔细分析,我们把getEvents方法也分成了三个部分去解析,分别是:打开设备部分;事件读取部分;等待部分。这三个部分中,以事件的读取部分为重点。设备打开部分一般发生在Input系统建立的时候调用,所以在系统启动完成,稳定之后,这部分内容应该不会再被执行的;而等待部分较为简单。不过这些作为系统必不可少的部分,还是要一一说明的,先说设备打开部分吧,代码如下:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ...
    struct input_event readBuffer[bufferSize];
    //这是元事件指针,可以指向一系列的事件,这些事件按照数组的方式存放的
    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        //mNeedToReopenDevices = false;

        //mClosingDevices = 0;

        //mNeedToSendFinishedDeviceScan = false;

        //mOpeningDevices = 0

        //mNeedToScanDevices = true
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }
    ...

EventHub对象在初始化的时候,有很多变量都已经赋值,所以我把代码中判断不成立的代码块暂时都拿掉了,只留下了在Input系统启动时候会执行的内容,

也就是scanDevicesLocked方法。在这个方法执行之后,肯定会产生一些设备添加,移除之类的事件,到时候在一一分析。

在这个方法中,使用了一个结构体叫RawEvent,使用这个结构体简单地表明事件发生的基本信息,代码如下:

struct RawEvent {
    nsecs_t when;//事件发生的时间,在getEvents中对于事件时间的处理也是值得关注的
    int32_t deviceId;//产生这个事件对应的设备的ID,与具体的硬件无关,其数值和设备打开的顺序有关
    int32_t type;//事件的类型
    int32_t code;//事件对应的事件码
    int32_t value;//事件的内容
};

RawEvent来自两种,一种是在打开设备时自己赋值,不如设备的添加,移除等,这些事件对应的RawEvent都是getEvents自己赋值的,便于InputReader处理;

还有一种是来自驱动的产生的事件,由驱动产生的这类事件,在内容中有其自己的定义的类型,就是input_event。

getEvents可以根据input_event产生相应的RawEvent便于InputReader处理。

这里要额外说明一点的就是RawEvent的type,如果是由输入设备产生的事件,那么这个type是和输入设备本身的特性相关的,

下面列举出Linux中支持的事件类型:

EV_SYN 用于标识独立的事件,这些独立的事件时在时间或者空间上是可以分离的,比如在多点触摸中
EV_KEY 用于标识按键,按钮或者类似按键的设备状态的变化
EV_REL 用于描述 对于轴线相对变化量,如鼠标向左移动5个单位
EV_ABS 用于描述 对于轴线的绝对变化量, 比如在触摸屏上的触摸点的坐标
EV_SW 标识二进制的开关状态
EV_LED 表示设备上的LED是开or关
EV_SND 用于标识发送声音到设备
EV_REP 表示自动重复的设备
V_FF 用于标识发送强制要回馈的命令到设备
EV_PWR 对于Power键的一个特殊状态或者切换输入
EV_FF_STATUS 用于收到需要强制回馈的设备状态
EV_MSC 如果不是这些已存在的状态,那么就用这个标识

这个表格来自于Linux内核文档中的Document/input/event-codes.txt,如果以上有翻译不恰当的地方,可以去参考原文档。上面这些类型是Linux支持的所有的事件类型,一般的一类设备可以支持这些类型中的一个或几个。

在Android系统中,常用的设备由触摸屏,键盘或者鼠标等,这些设备一般是能够产生如下类型的事件:

多点触屏    大多是EV_ABS, EV_KEY, EV_SYN,有的还设置了EV_MSC
键盘         EV_KEY, EV_SW
鼠标        EV_REL, EV_KEY, EV_ABS

这个表格仅仅是一般性而言,具体情况还需要参考相应的设备驱动文件。这里之所以介绍这些东西,是因为在InputReader在预处理这些事件的时候会使用type这个类型。了解了这些之后,继续看EventHub是如何打开这些设备的。 EventHub是通过扫描/dev/input/目录下所有可用的设备,然后逐一打开这些设备,打开这些设备过程中,EventHub又做了一些Input系统必要的工作,比如构造Device对象,把这些设备加入到epoll的监视队列中等,时间戳的设定等。在构造Device对象的时候,是通过InputDeviceIdentifier来构造的,主要思路就是通过ioctl函数从内容中读取出一些必要的信息,然后把这些信息经过InputDeviceIdentifier存入Device中,然后再通过ioctl函数测试设备的属性,把这些属性信息也存入Device中。代码如下:

static const char *DEVICE_PATH = "/dev/input";

void EventHub::scanDevicesLocked() {
    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();
    }
}

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++ = '/';
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
}

#define EVIOCGNAME(len)        _IOC(_IOC_READ, 'E', 0x06, len)        /* get device name */

status_t EventHub::openDeviceLocked(const char *devicePath) {
    ...
    InputDeviceIdentifier identifier;

    // 获取设备的名字,如果成功获取到设备的名字,把它存入InputDeviceIdentifier中
    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);
    }
    ...
    //构造EventHub所需要的对象Device,这里的fd是刚刚打开的设备的文件描述符
    int32_t deviceId = mNextDeviceId++;//从这里可以看出,deviceId是与设备无关的,和打开顺序有关
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

    // 测试设备能够产生的事件的类型,这些事件类型在前文中已经说到过。这里就是Android支持的事件类型,是Kernel的一个子集
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
    ...
    //根据前面获取到的设备属性,检测设备是鼠标,键盘,手柄等,然后把这些信息继续存入Device
    if (test_bit(BTN_MOUSE, device->keyBitmask)
            && test_bit(REL_X, device->relBitmask)
            && test_bit(REL_Y, device->relBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_CURSOR;
    }
    ...

这部分代码,把InputDeviceIdentifier转化为了Device,因为Device能够存储更多的信息,是EventHub所需要的。

在打开设备的时候对这些Device完成了初始化。然后就是把这些设备加入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;
    }

如此之后,只要设备有输入事件的产生,通过epoll就能从阻塞中返回。之后就是设置设备的硬件时钟。在报告事件的时候,我们要使用的时钟是monotonic clock, 这时钟的特点就是在每次开机的时候初始化为0。

事件发生时的时间戳在input系统中使用非常广泛,而且Input系统会假设事件的时间戳是monotonic的时间点。

最后把这些设备添加到EventHub的一个Vector中,类似如下格式:

deviceId Device*
1 Device*
2 Device*
... ...

这个数组将会在EventHub中广泛地使用,经常使用的方式是通过deviceId获取Device设备。到这里,打开设备的工作已经完成,而且为EventHub的工作创建了一些有用的变量和数组等。

EventHub中的第一个功能,打开设备已经完成。接着我们在看看事件等待部分,最后再说事件的读取。其实事件的等待部分很简单,主要的代码就一行,如下:

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

注意代码中的最后一个参数timeoutMillis,前面已经说到过,一般来说这个参数是-1,意味着线程会在这个地方阻塞,无限等待下去,直到有事件的发生,而在新的设备加入的时候,这个值为0,意味着可以立即返回。

所以,在系统启动完成后,如果没有事件发生的话,InputReaderThread线程会阻塞在这里,一直等待事件的发生。最后,我们看看事件的读取部分,代码如下:

bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            ...//这里省略了对于其他的epoll类型的处理。如果是EPOLLIN类型的事件,意味着epoll监视的文件描述符中有写入事件,这类事件是输入事件,
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {//从产生事件的描述符中读取出事件,放入readerBuffer
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    deviceChanged = true;
                    closeDeviceLocked(device);
                } else if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        ALOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ALOGE("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];
                        ...//这里省略了对于事件时间戳的设定,考虑的因素挺多,虽时间戳对于输入事件很重要,但是不应该是本次讨论的重点
                        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) {
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            }
            ...
        }

其实这段代码也是非常简单的,基本过程就是,监视到有事件的产生,把事件读取出来,不过这里读出的事件是input_event类型的,然后在逐个把input_event事件转化为InputReader需要的RawEvent类型的事件,放入InputReader提供给EventHub的数组中(通过getEvents参数传递进来的)。说起来很简单,其实也很简单。上面这些代码就是读取事件的核心部分。

总结一下,EventHub负责打开/dev/input/目录下的所有设备,然后为每一个设备创建一个Device,并把这个Device放入EventHub所定义的数组们Device中。之后,就是把这个设备纳入监视范围。然后就是开始等待事件的发生,一旦有事件发生,就从产生事件的设备中读取出这些设备,把这些事件转化为RawEvent类型放入InputReader提供的事件数组中,之后返回。到这里,从EventHub获取事件就结束了。

阶段二,InputReader对元事件的处理

由上节的内容,我们知道,从EventHub获得的事件有两种,一种是设备添加,移除类的;另一种是由输入设备产生的事件。InputReader在处理这两类事件稍微有点不一样。先看设备添加类型的事件,这些添加设备事件的处理,为InputReader的工作打下了基础,因为InputReader可以根据添加的设备定义一些数据结构,为以后处理由此设备产生的事件打下基础。接着我们从代码开始看看InputReader对于元事件的处理:
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);
        } else {
            switch (rawEvent->type) {//设备添加类的事件在这里处理
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);//这个方法中创建了InputReader所必须的一些数据结构
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

 先从设备添加类的事件说起,看看在添加设备的时候,都创建了那些数据结构。对于addDeviceLocked的源码,这里就不列举出来,主要说说在InputReader在功能实现时用的变量有那些,分别是是InputDevice,InputMapper。InputDevice代表输入设备的一个状态;InputMapper是某一类事件是如何处理的;两者之间的关系是,一个InputDevice可以产生多种类型的事件,因此他可以对应多个InputMapper。另外,在InputReader中也保存了一个vector来保存InputDevice,这个Vector的名字也叫mDevices,和EventHub中的mDevices类似,不过保存的内容有些不同。在InputReader的mDevices中保存的,而在EventHub中保存的是,不过两者的id是一致的,而且每个InputDevice都是通过Devices来构造的。能够完成加工RawEvent工作的还是通过不同的InputMapper来完成的,这些InputMapper根据Android系统支持的类型分成了一下几类,

InputMapper类型 能够处理的事件的类型
SwitchInputMapper EV_SW, EV_SYN
KeyboardInputMapper EV_KEY, EV_SYN, EV_MSC
CursorInputMapper EV_KEY, EV_SYN, EV_REL
TouchInputMapper EV_KEY, EV_SYN, EV_REL
SingleTouchInputMapper EV_KEY, EV_SYN, EV_REL, EV_ABS
MultiTouchInputMapper EV_KEY, EV_SYN, EV_REL, EV_ABS
JoyStickInputMapper EV_ABS, EV_SYN
VibratorInputMapper --
这里就基本完成了对于添加设备类的事件的处理,接下来就看是分析对于输入设备产生的元事件的处理。对于输入事件的处理主要是通过方法processEventsForDeviceLocked进行的,在这个方法执行之前,已经找到了产生这个事件的输入设备了,然后把输入设备作为参数传递进去,processEventsForDeviceLocked方法根据deviceId找到相应的InputDevice,然后调用InputDevice的process方法进行处理这个事件。下面,结合InputDevice的process方法的这段代码,我们一起看看输入事件是如何处理的,代码如下:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
            ...//省略了一些与判断的处理,留下核心部分的代码
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);//让各个InputMapper去处理元事件,注意参数还是RawEvent类型
            }
    }
    
}

在这个方法中,注意有内外两个循环,外循环是逐一取出元事件,内循环是让每一个InputMapper都处理这个事件。之所以让每一个InputMapper都进行处理元事件,而不是只要对应的InputMapper去处理,是因为担心只让对应的InputMapper处理元事件会产生副作用,比如For example, joystick movement events and gamepad button presses are handled by different mappers but they should be dispatched in the order received. 对于每一个InputMapper都要处理元事件,我们不做一一分析,仅仅拿出典型的键盘输入事件分析。处理过程如下:

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY: {
        int32_t scanCode = rawEvent->code;
        int32_t usageCode = mCurrentHidUsage;
        mCurrentHidUsage = 0;

        if (isKeyboardOrGamepadKey(scanCode)) {
            int32_t keyCode;
            uint32_t flags;
            if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
                keyCode = AKEYCODE_UNKNOWN;
                flags = 0;
            }
            processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
        }
        break;
    }
 ...//省略了对于其他事件类型EV_SYN, EV_MSC的处理代码
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
        int32_t scanCode, uint32_t policyFlags) {
    ...//省略了对于元事件处理过程的代码,主要就是发生事件,事件代码,扫描码,是按下还是弹起,
    //总之,用于构建下面NotifyKeyArgs的参数大都是在这里获取的。
    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
    getListener()->notifyKey(&args);
}

这是InputReader对于元事件处理的过程。在处理完成后,在最后调用了一个重要的方法getListener()->notifyKey(&args)方法。在InputReader处理各种元事件的时候,基本过程都是这样的,把元事件中的各项信息构建一个NotifyArgs,然后通过QueuedInputListener来通知InputDispatcher。由此,InputReader的处理过程开始进入了和InputDispatcher交互的阶段。其实在QueuedInputListener中对于notifyKey的实现非常简单,仅仅是把这些事件的参数压入队列而已,并没有做太多的操作就返回了。

阶段三,InputReader把事件发送到InputDispatcher

前面我们已经知道了,InputReader把元事件处理完毕后,构造了一个NotifyArgs,并把这个对象压入了QueuedInputListener的队列中,然后就返回了。当时我们并不知道如何把这些队列中的事件发送的InputDispatcher中的。这里,就给出了这个过程。InputReader调用QueuedInputListener的flush方法,把QueuedInputListener队列中的所有事件都发送到InputDispatcher中。下面我们就分析这个过程,从QueuedInputListener的flush方法说起,代码如下:

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();//前面,我们就是把NotifyArgs放入了mArgsQueue中
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);//逐个取出NotifyArgs,然后调用notify方法,注意这里面的参数是mInnerListener,是InputDispatcher
        delete args;
    }
    mArgsQueue.clear();
}

这里从队列中逐个取出NotifyArgs,然后调用他们的notify方法。在QueuedInputListener创建的时候,我们传入构造函数的的参数是一个InputDispatcher,在这里就使用到了,把这个InputDispatcher作为参数向下传递。在NotifyArgs的notify方法中,基本都类似于

void NotifyKeyArgs::notify(const sp& listener) const {
    listener->notifyKey(this);//调用InputDispatcher的对应的方法。
}
到这里,我们对于InputReader的功能的分析就完成了。
总结一下,基本过程说就是:InputReader从EventHub中读取出来元事件,预处理加工这些元事件成为NotifyArgs,然后通过QueuedInputListener把他们通知给InputDispatcher。
接下来讲 InputDispatcher对事件分发的流程。
InputDispatcher的功能和流程

在开始介绍InputDispatcher的功能之前,先看看Android文档对于其功能的描述:把输入事件发送到他的目标中去。他的目标可能是应用程序,也可能是WindowManagerService。如果是应用程序的话,可以通过registerInputChannel来定义输入事件的目标。我们已经了解InputDispatcher的唯一一个功能就是分发事件。知道了其功能之后,我们就开始分析InputDispatcher是如何实现这些功能的吧。先看他的构造函数,InputDispatcher创建了一个Looper,代码如下:

mLooper = new Looper(false);
这意味着,InputDispatcher有自己的Looper,没有和别人共用,信息也是自己在循环的。这个Looper是native层的Looper,由C++代码实现。在构建Looper过程中,新建了一个管道,这个管道仅仅起到了唤醒Looper,让其能从阻塞等待中返回。Looper中创建的管道是实现Looper功能的重要的方式,是通用的,不是仅仅为了InputDispatcher准备的。看完构造函数之后,我们接着分析InputDispatcher的功能,接着上节中的QueuedInputListener通知InputDispatcher有新的按键事件说起。这里还是接着上面的以按键的处理,接着看InputDispatcher是如何实现分发的,代码如下:

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    ...
    KeyEvent event;//在这里通过传递进来的NotifyArgs为参数,构建KeyEvent
    event.initialize(args->deviceId, args->source, args->action,
            flags, args->keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);
  //通过NativeInputManager把这个KeyEvent最终传递给WindowManagerService去处理,最终返回policyFlags
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/policyFlags);//阶段一,事件在入队前(before enqueue)的处理
    ...
    bool needWake;
    ...
        int32_t repeatCount = 0;//这下面构建KeyEntry
        KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, args->keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);
        //会将事件实例newEntry推送到mInboundQueue,后续InputDispatcher的线程会从mInboundQueue采集事件并进行处理和分发
        needWake = enqueueInboundEventLocked(newEntry);//阶段二,事件的入队处理
        mLock.unlock();

    if (needWake) {//唤醒等待Looper,进行事件处理和分发
        mLooper->wake();
    }
}

我们先从代码中的line 8开始,这行代码的意思是,把KeyEvent发送出去,至于目的地是哪儿,在InputDispatcherPolicy中会有决定。是NativeInputManager实现了这个Policy,所以代码的执行会进入NativeInputManager中。

阶段一、事件在入队前(before enqueue)的处理

在文章的前面已经说到过,NativeInputManager负责和系统的其他模块交互--是其功能之一。

把这个KeyEvent传递到NativeInputManager之后,继续分发,最终会把这个KeyEvent传递到PhoneWindowManager中去处理这个事件,返回wmActions,传递过程如下:

NativeInputManager->interceptKeyBeforeQueueing  ---->

InputManagerService.interceptKeyBeforeQueueing ---->

InputMonitor.interceptKeyBeforeQueueing ----> 

PhoneWindowManager.interceptKeyBeforeQueueing.

大致过程是这样。

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {
    if ((policyFlags & POLICY_FLAG_TRUSTED)) {
        nsecs_t when = keyEvent->getEventTime();
        bool isScreenOn = this->isScreenOn();
        bool isScreenBright = this->isScreenBright();
        JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        jint wmActions;
        if (keyEventObj) {

            //调用InputManagerService.java的interceptKeyBeforeQueueing方法,policyFlags为处理结果
            wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing, keyEventObj,policyFlags, isScreenOn);

            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                wmActions = 0;
            }
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
        } else {
            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
            wmActions = 0;
        }
        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
            if (!isScreenOn) {
                policyFlags |= POLICY_FLAG_WOKE_HERE;
            }
            if (!isScreenBright) {
                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
            }
        }
        handleInterceptActions(wmActions, when, /*byref*/policyFlags);//
    } else {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    }
}

//处理按键事件

void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Going to sleep.");
#endif
        android_server_PowerManagerService_goToSleep(when);//休眠
    }

    if (wmActions & WM_ACTION_WAKE_UP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Waking up.");
#endif
        android_server_PowerManagerService_wakeUp(when);//唤醒
    }

    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;//反馈给应用
    } else {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Not passing key to user.");
#endif
    }
}

在传递过程中是跨线程的。通过这一系列的方法的名字可以看出,是在事件进入InputDispatcher的队列之前,进行的一些处理。在PhoneWindowManager处理事件之后,会有一个返回值来标记这一事件处理的结果是怎样的,为后面的事件进入队列做准备。在PhoneWindowManager对事件进行前期的拦截处理过程时,一般首先把事件都标记上PASS_TO_USER,即这个事件要交给应用程序去处理,但是在处理过程中决定,有些事件是没必要传递给应用程序的,

比如:在通过过程中按下音量相关的事件,挂断电话的事件,power键的处理,以及拨打电话的事件。这些事件的处理结果都是不必传递到应用程序的,这个结果为返回值,最终会一步一步地返回到NativeInputManager中,这个返回值会作为NativeInputManager的policyFlags的一部分,供InputDispatcher使用。在PhoneWindowManager对事件处理完成后,才会把这个事件构造成为一个形式为EventEntry放入队列。到这里,我们的工作仍在InputReaderThread的线程中,虽然是对InputDispatcher的操作

阶段二、事件的入队(enqueue in bound)处理

enqueueInboundEventLocked会将事件实例推送到mInboundQueue,在这里,InputDispatcher的线程会从mInboundQueue采集事件并进行处理和分发。

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry);
    traceInboundQueueLengthLocked();

    switch (entry->type) {
    case EventEntry::TYPE_KEY: {
        KeyEntry* keyEntry = static_cast(entry);
        if (isAppSwitchKeyEventLocked(keyEntry)) {
            if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                mAppSwitchSawKeyDown = true;
            } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
                    ALOGD("App switch is pending!");
#endif
                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
                    mAppSwitchSawKeyDown = false;
                    needWake = true;
                }
            }
        }
        break;
    }

    case EventEntry::TYPE_MOTION: {
    .............
        break;
    }
    }
    return needWake;
}

执行InputDisatcherTread线程

接下来才是真正进入InputDispatcherTread线程对InputDispatcher操作。通过InputDispatcher的mLooper的wake方法,唤醒InputDispatcherThread线程。

关于Looper如何在wake时是如何通过管道的方式去实现的,这个过程应该放在一篇单独的文章中详细地去说明,在以后的文章中,我会说到Looper在native实现时的一些特点的。

这里,我们知道InputDispatcherThread线程被唤醒了。如果你已忘记InputDispatcherThread线程是何时被阻塞,那就回头再重新看看吧。学习别人的思路就是这样,反复回头看,才能不至于迷失在别人的思维中。

最初启动InputDispatcherThread线程的时候,第一次调用mLooper->pollOnce之后处于睡眠状态,在InputReaderThread线程中执行mLooper->wake()进行唤醒。

然后就开始执行InputDispatcher的threadLoop函数,之后就调用InputDispatcher的dispatchOnce方法,代码如下:

bool InputDispatcherThread::threadLoop() {

    mDispatcher->dispatchOnce();

    return true;

}

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;//应该是64位二进制所能表示的最大值,大概是2^63-1,即9223372036854775807
    {
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();
    //如果没有等待执行的命令的话,就开始一次循环分发。在循环过程中,可能会有一些命令产生。这里的命令大概是模式设计中的:命令模式吧
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);//阶段一,事件分发
        }
    //如果任何等待执行的命令的话,那么就执行这些命令;假如有命令已经执行了,那么下次poll的时候直接唤醒
        if (runCommandsLockedInterruptible()) {//阶段二,事件执行
            nextWakeupTime = LONG_LONG_MIN;//#define LONG_LONG_MIN  (-__LONG_LONG_MAX__-1LL), 即-9223372036854775808
        }
    } // release lock

    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);

    //阶段三,InputDispatcherThread线程被阻塞,因为InputReaderTread和InputDispatcherThread共享一个InputDispatcher变量,所以能够通过mLooper控制InputDispatcherThread线程的sleep和wake

   //mDispatcher = new InputDispatcher(dispatcherPolicy);

  //mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    mLooper->pollOnce(timeoutMillis);
}

阶段一、事件分发

 InputDispatcher的主要功能就在这段代码中,这是个轮廓。要想知道具体的功能的实现,还要需要逐步分析下去。先看line7和line8中的代码,如果是一次正常的分发循环(dispatch loop)的话,应该是没有等待执行的命令。为什么会没有等待执行的命令,在后面会说到原因,先不要着急。所以接下就开始dispatchOnceInnerLocke方法,从这个方法的名字可以看出,这应该是功能的核心实现部分。看其代码是如何实现的:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
   //如果等待处理的事件不存在的话
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            ...//省略了,当等待处理事件不存在且事件队列为空的时候的处理
        } else {//从事件队列的头部取出一个事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
          //通知某些Activity一些事件的发生,通过这个方法的名字可以联想一下,一些社交网站中的“捅一下”应用,或者QQ中的震动窗口功能,
            pokeUserActivityLocked(mPendingEvent);//这个方法的功能就类似于那些作用。只不过这里主要是用来“捅一下”PowerManagerService的
        }

        // Get ready to dispatch the event.
        resetANRTimeoutsLocked();
    }
  //现在我们有事件需要开始处理了
    ALOG_ASSERT(mPendingEvent != NULL);
    bool done = false;
    DropReason dropReason = DROP_REASON_NOT_DROPPED;//在开始处理之前,所有的事件都不必丢弃
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {
        dropReason = DROP_REASON_DISABLED;
    }

    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }

    switch (mPendingEvent->type) {
...//省略了对于config change类别的事件的处理
...//省略了对于设备重置事件的处理
    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast(mPendingEvent);
        if (isAppSwitchDue) {//下面这些内容,是对于事件是否需要丢弃的分析
            if (isAppSwitchKeyEventLocked(typedEntry)) {
                resetPendingAppSwitchLocked(true);
                isAppSwitchDue = false;
            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }//无论事件是否要被丢弃,都要经过如下的处理
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }
    ...//省略了对于motion事件的处理
    }
    ...
}

这个方法中的大部分功能都已经在代码中注释了,主要就是取出事件,分析是否需要丢弃,然后就是开始按照类型分发事件,我们假设的是按键事件,所以接下来就是调用dispatchKeyLocked方法来分发。

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    if (! entry->dispatchInProgress) {
        ...//省略了对于重复事件在各种情况下的处理
    }

   ...//在入队列之前,对于事件有个一次intercept,这里是对事件的intercept结果的处理
    Vector inputTargets;
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);//寻找事件发送到的目标窗口
     // 分发事件
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

这个方法中主要就是寻找到事件应该分发到的目标,可能是应用窗口.这个目标应用的窗口寻找与应用程序启动时设置到窗口有关。在下一小节中会说到这个窗口是如何找到的。其代码不是很复杂,自己看看的话也很容易能够明白。其他的内容在上面的注释中也有说明。下面还是将注意力集中在事件分发上,注意这里传入dispatchEventLocked的参数中inputTargets是复数,也就是说可能有多个目标。所以在方法dispatchEventLocked中就是根据每一个target对应的inputChannel找到connection,然后 prepareDispatchCycleLocked使用这个connection把事件逐个分发到target中。 在prepareDispatchCycleLocked方法中,主要就是根据事件是否可以分割,分别把事件放入队列。在入队列的之后,InputPublisher的发布事件的队列就不再为空,然后会调用 startDispatchCycleLocked方法,通过InputPublisher开始发布事件。大致过程如此,为了减少篇幅,这里就不再列出代码了

dispatchEventLocked——》prepareDispatchCycleLocked——》enqueueDispatchEntriesLocked——》startDispatchCycleLocked

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();

    // Enqueue dispatch entries for the requested modes.
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_IS);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

    // If the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp& connection) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ startDispatchCycle",
            connection->getInputChannelName());
#endif

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast(eventEntry);

            // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
            break;
        }

.......................

}

阶段二、事件执行

在前面我们说到过这么一个问题,等待执行的命令为什么在一次正常的事件分发之后应该为空?这些命令产生的地方分别在pokeUserActivity方法中, 和dispatchKeyLocked中等等在使用postCommand把命令放入队列的地方。在上面这个过程执行完毕后,会返回到dispatchOnce方法中,接着往下执行,也就是执行代码:

bool InputDispatcher::runCommandsLockedInterruptible() {
    if (mCommandQueue.isEmpty()) {
        return false;
    }
    do {
        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
        Command command = commandEntry->command;
        (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'

        commandEntry->connection.clear();
        delete commandEntry;
    } while (! mCommandQueue.isEmpty());
    return true;
}

也就是前面dispatchOnce方法的line 11. 这个方法的功能就是执行之前放入命令队列的命令。具体的代码不再列出。

阶段三、阻塞InputDispatcher线程

int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    inline int pollOnce(int timeoutMillis) {
        return pollOnce(timeoutMillis, NULL, NULL, NULL);
    }

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }

        result = pollInner(timeoutMillis);

    }
}
说明一点:Looper到InputDispatcher中的dispatcherOnce不是调用关系,只是Looper把其所在的进程即InputDispatcherThread线程给唤醒,所以开始执行dispatchOnce。这里到最后就是调用InputPublisher的publishKeyEvent方法,把事件发布出去。

到这里,关于InputDispatcher的功能--唯一的一个功能--事件分发,就算介绍完了。


你可能感兴趣的:(android4.4电源管理——Input系统(Power键处理))