Android | InputManagerService与输入

作者: 彭旭锐 | 来源:发表于2019-07-26 23:25 被阅读299次

    前言

    • 事件分发机制是Android中的基础而重要的知识,一般认为Activity#dispatchKeyEvent()或者Activity#dispatchTouchEvent()是分发的起点。那么问题来了,是谁调用了Activity的方法呢?输入事件是如何产生的?
    • Android系统有一整套从Linux内核应用框架层应用层的事件处理机制
    • 本文将以InputManagerService为线索,分析输入事件的产生-采集-分发流程,希望能帮上忙
    思维导图 输入事件 示意图

    1. 启动服务

    Android系统启动后,系统进程SystemServer.java将依次启动各个系统服务,我们搜索下InputManagerService,不会匹配到太多东西,梳理一下有关的代码:

    关于系统服务的更多介绍参考:[Android | 系统启动过程]

    // /frameworks/base/services/java/com/android/server/SystemServer.java
    private void startBootstrapServices() {
        InputManagerService inputManager = null;
        WindowManagerService wm = null;
            
        // ...
            
        // 实例化InputManagerService
        inputManager = new InputManagerService(context);
        // 实例化WindowManagerService
        wm = WindowManagerService.main(context,inputManager,...);
        // 添加到ServiceManager统一管理
        ServiceManager.addService(Context.WINDOW_SERVICE, wm, ...);
        ServiceManager.addService(Context.INPUT_SERVICE, inputManager,...);
            
        // ...
            
        inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
        // 启动InputManager服务
        inputManager.start();
    }
    
    IMS与WMS UML类图

    可以看出,系统进程分别实例化了InputManagerServiceWindowManagerService,前者的实例直接传入后者,而后者又传递了一个InputMonitor对象给前者,这是为什么呢?暂时跳过,继续往下看InputManagerService.java

    // /frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
    
    private static native long nativeInit(InputManagerService service,Context context, MessageQueue messageQueue);
    
    private static native void nativeStart(long ptr);
    
    public InputManagerService(Context context) {
        // ...
        // 调用了native层
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
        // ...
    }
    
    public void start() {
        // 调用了native层
        nativeStart(mPtr);
        // ...
    }
    

    这里只是调用到native层的两个静态方法,继续往下看com_android_server_input_InputManagerService.cpp

    // /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
    
    static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
        // ...
        // 实例化NativeInputManager对象
        NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());
        im->incStrong(0);
        return reinterpret_cast<jlong>(im);
    }
    
    static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
        // 调用到InputManager#start()
        status_t result = im->getInputManager()->start();
    }
    
    NativeInputManager::NativeInputManager(jobject contextObj, 
            jobject serviceObj, const sp<Looper>& looper) : 
        mLooper(looper), mInteractive(true) {
        // ...
        // 实例化EventHub对象
        sp<EventHub> eventHub = new EventHub();
        // 实例化InputManager对象
        mInputManager = new InputManager(eventHub, this, this);
    }
    
    public: 
    inline sp<InputManager> getInputManager() const { return mInputManager; }
    

    可以看出,在native层实例化了NativeInputManager,其构造方法里还实例化了InputManagerEventHub对象,后者是干什么的呢?暂时跳过,继续往下看InputManager.cpp

    // /frameworks/native/services/inputflinger/InputManager.cpp
    
    InputManager::InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        // 实例化InputDispatcher与InputReader
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        // InputDispatcher实例与EventHub实例传递给InputReader
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        initialize();
    }
    
    void InputManager::initialize() {
        // 实例化两个线程
        mReaderThread = new InputReaderThread(mReader);
        mDispatcherThread = new InputDispatcherThread(mDispatcher);
    }
    
    status_t InputManager::start() {
        // 运行两个线程
        status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
        result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
        // ...
    }
    

    可以看出,InputManager的构造方法中实例化了InputDispatcherInputReader,随后start()中启动了InputDispatcherThread线程与InputReaderThread线程(继承于Thread.cpp)。

    Timethreads图 - 01

    这两个线程分别做什么事呢?继续往下看InputReder.cppInputDispatcher.cpp

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : 
    // 继承于Thread
    Thread(/*canCallJava*/ true), mReader(reader) {
    }
    
    /**
     * true:循环执行threadLoop()直到调用requireExit()退出循环
     **/
    bool InputReaderThread::threadLoop() {
        // 读取/采集一次事件
        mReader->loopOnce();
        return true;
    }
    
    // /frameworks/native/services/inputflinger/InputDispatcher.cpp
    
    InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
    }
    
    bool InputDispatcherThread::threadLoop() {
        // 分发一次事件
        mDispatcher->dispatchOnce();
        return true;
    }
    

    可以看到,到这里InputManagerService的启动就完成了,提炼出关键点:

    • InputManagerServiceWindowManagerService运行在系统进程SystemServer
    • InputManagerService启动了InputReaderThread线程与InputDispatcherThread线程,分别死循环调用InputReader#loopOnce()InputDispatcher#dispatchOnce()
    Timethreads图 - 02

    2. 采集事件

    上一节讲到,InputReaderThread线程死循环执行InputReader#loopOnce(),用于采集事件,简化代码如下:

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    void InputReader::loopOnce() {
        // ...
        // 从EventHub中读取事件,存储在指针mEventBuffer中
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
        if (count) {
            // 处理读取到的事件
            processEventsLocked(mEventBuffer, count);
        }
        // ...
        // 这一行是干什么的?稍后介绍
        mQueuedListener->flush();
    }
    
    void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
        // 遍历每个事件
        for (const RawEvent* rawEvent = rawEvents; count;) {
            // ...
            int32_t type = rawEvent->type;
            if(type <  EventHubInterface::FIRST_SYNTHETIC_EVENT){
                // 分支1:输入事件
                // ...
                            
                // 处理每一个输入事件
                int32_t deviceId = rawEvent->deviceId;
                processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
            }else{
                // 分支2:设备事件
                switch(rawEvent->type){
                        case EventHubInterface::DEVICE_ADDED:
                            addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                            break;
                           // ...
                }
            }
        }
        // ...
    }
    

    可以看到,loopOnce()EventHub实例中获取到原始事件,并依次处理每个事件,分为两种:

    • 输入事件(分支1)
    • 设备事件(分支2)

    我们先看分支1的processEventsForDeviceLocked(),简化代码如下:

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) {
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
        // ...
        InputDevice* device = mDevices.valueAt(deviceIndex);
        // ...
        device->process(rawEvents, count);
    }
    
    void InputDevice::process(const RawEvent* rawEvents, size_t count) {
        size_t numMappers = mMappers.size();
        // 遍历每个事件
        for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
                // 依次交给每个InputMapper处理
                for (size_t i = 0; i < numMappers; i++) {
                        InputMapper* mapper = mMappers[i];
                        mapper->process(rawEvent);
                }
        }
    }
    

    可以看到,输入事件交给了InputDevice处理,在内部实际上是执行了多次InputMapper#process(),这里的InputDeviceInputMapper是什么呢,还记得分支2的addDeviceLocked()吗?简化代码如下:

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
        // ...
        // 创建InputDevice实例
        InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
        // ...
        // 添加到mDevices列表 
        // InputReader.h:KeyedVector<int32_t, InputDevice*> mDevices;
        mDevices.add(deviceId, device);
        // ...
    }
    
    InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) {
        // 创建InputDevice实例
        InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes);
    
        // ...
            
        // Scroll wheel-like devices. - 滚轮式
        if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
            device->addMapper(new RotaryEncoderInputMapper(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));
        }
            // ...
    }
    

    可以看到分支2里,先创建了InputDevice实例,随后根据不同的设备事件的类型,又添加了不同InputMapper,比如滚轮式,触屏式,操纵杆式,这也就说明了,一个Android设备上是支持同时接入多个输入设备的,当然触屏设备才是本文分析的重点。

    让我们回到分支1的InputMapper#process(),因为我们的重点是触屏设备,所以我们只关心MultiTouchInputMapperSingleTouchInputMapper,代码如下:

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    // 多点触控设备
    void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
        TouchInputMapper::process(rawEvent);
        // ...
    }
    
    // 单点触控设备
    void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
        TouchInputMapper::process(rawEvent);
        // ...
    }
    
    void TouchInputMapper::process(const RawEvent* rawEvent) {
        // ...
        if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
            sync(rawEvent->when);
        }
    }
    
    void TouchInputMapper::sync(nsecs_t when) {
        // ...
        processRawTouches(false /*timeout*/);
    }
    
    void TouchInputMapper::processRawTouches(bool timeout) {
        // ...
        cookAndDispatch(mCurrentRawState.when);
    }
    
    void TouchInputMapper::cookAndDispatch(nsecs_t when) {
        // ...
            
        // 按键事件
        if (consumeRawTouches(when, policyFlags)) {
            mCurrentRawState.rawPointerData.clear();
        }
        // ...
        // 触点事件
        dispatchPointerUsage(when, policyFlags, pointerUsage);
        // ...
    }
    

    从简化的代码可以看出,不论是MultiTouchInputMapper还是SingleTouchInputMapper,最终都会走到cookAndDispatch()这个方法,分别处理了两类事件:

    • 按键事件
    • 触点事件
    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
        // ...
        // 处理虚拟按键事件
        dispatchVirtualKey(...)
        // ...
    }
    
    void TouchInputMapper::dispatchVirtualKey(...) {
        // ...
        // 实例化一个NotifyKeyArgs
        NotifyKeyArgs args(...);
        // 回调
        getListener()->notifyKey(&args);
    }
    
    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage) {
        // ...
        // 处理触点事件
        dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
        // ...
    }
    
    void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) {
        // ...
        // 处理触点事件
        dispatchMotion(...)
        // ...
    }
    
    void TouchInputMapper::dispatchMotion(...){
        // ...
        // 实例化一个NotifyMotionArgs
        NotifyMotionArgs args(...);
        // 回调
        getListener()->notifyMotion(&args);
    }
    

    从简化代码可以看出,对于按键事件和触点事件,分别实例化了NotifyKeyArgsNotifyMotionArgs,随后分别调用了getListener()->notifyKey()getListener()->notifyMotion()

    事件采集 UML时序图 - 01

    getListener()->notifyKey()看起来很像是告知监听器已经采集到事件了,是不是这样呢?找一下getListener()相关代码:

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    InputListenerInterface* InputReader::ContextImpl::getListener() {
        // 弱指针的用法,简单理解为返回了mQueuedListener就好
        return mReader->mQueuedListener.get();
    }
    
    // --- InputReader ---
    
    InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) {
        // 实例化QueuedInputListener
        mQueuedListener = new QueuedInputListener(listener);
    }
    

    可以看出,getListener()的返回值是mQueuedListener,返回值类型是InputListenerInterface,它在InputReader的构造方法中创建,并包装了InputReader构造方法的第三个参数listener,这个listener又是什么呢?让我们回去找到实例化InputReader的地方:

    // /frameworks/native/services/inputflinger/InputManager.cpp
    
    InputManager::InputManager(...) {
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        // InputDispatcher实例与EventHub实例传递给InputReader
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        initialize();
    }
    

    原来如此,InputDispatcher实例就是这第三个参数listener,我们查看InputDispatcherInputListenerInterface的定义:InputDispatcher.hInputListener.h

    // /frameworks/native/services/inputflinger/InputDispatcher.h
    
    class InputDispatcher : public InputDispatcherInterface {
        // ...
    }
    
    class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
        //...
    }
    
    // /frameworks/native/services/inputflinger/InputListener.h
    
    /**
     * 基类
     **/
    struct NotifyArgs {
        virtual ~NotifyArgs() { }
        virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
    };
    
    /**
     * 触点事件
     **/
    struct NotifyMotionArgs : public NotifyArgs {
        // ...
    }
    
    /**
     * 按键事件
     **/
    struct NotifyKeyArgs : public NotifyArgs {
        // ...
    }
    
    class InputListenerInterface : public virtual RefBase {/**弱指针**/
        // ...
    public:
        virtual void notifyKey(const NotifyKeyArgs* args) = 0;
        virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
            
        // ...  
    };
    
    class QueuedInputListener : public InputListenerInterface {
        // ...
    public:
        explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
            
        virtual void notifyKey(const NotifyKeyArgs* args);
        virtual void notifyMotion(const NotifyMotionArgs* args);
            
        void flush();
            
        // ...
    
    private:
        sp<InputListenerInterface> mInnerListener;
        Vector<NotifyArgs*> mArgsQueue;
    };
    

    可以看到,QueuedInputListenerInputDispatcher都是实现了InputListenerInterface,前者其实就是后者的包装类。

    InputDispatcher UML类图

    我们看看包装类QueuedInputListener都做了什么,简化代码如下InputListener.cpp

    // /frameworks/native/services/inputflinger/InputListener.cpp
    
    void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
        // push到队列中
        mArgsQueue.push(new NotifyKeyArgs(*args));
    }
    
    void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
        // push到队列中
        mArgsQueue.push(new NotifyMotionArgs(*args));
    }
    
    void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
        listener->notifyMotion(this);
    }
    
    void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
        listener->notifyKey(this);
    }
    
    void QueuedInputListener::flush() {
        size_t count = mArgsQueue.size();
        // 遍历每个NotifyArgs
        for (size_t i = 0; i < count; i++) {
            NotifyArgs* args = mArgsQueue[i];
            // mInnerListener就是InputDispatcher
            args->notify(mInnerListener);
            delete args;
        }
        mArgsQueue.clear();
    }
    

    可以看到,之前的getListener()->notifyMotion()或者getListener()->notifyKey()都是把事件pushmArgsQueue队列中。那么队列中的这些事件到底什么时候才被处理呢?还记得InputReader#loopOnce()的最后一步吗?

    // /frameworks/native/services/inputflinger/InputReader.cpp
    
    void InputReader::loopOnce() {
        // ...
        // 从EventHub中读取事件,存储在指针mEventBuffer中
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
        if (count) {
            // 处理读取到的事件
            processEventsLocked(mEventBuffer, count);
        }
        // ...
        mQueuedListener->flush();
    }
    

    原来如此,所有事件被pushmArgsQueue队列之后,会调用mQueuedListener->flush(),最终会调用到InputDispatcher#notifyKey()InputDispatcher#notifyMotion(),归纳时序图如下:

    事件采集 UML时序图 - 02

    继续查看InputDispatcher#notifyKey()InputDispatcher#notifyMotion()的简化代码:

    // /frameworks/native/services/inputflinger/InputDispatcher.cpp
    
    void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
        // ...
            
        // 实例化KeyEntry
        KeyEntry* newEntry = new KeyEntry(...);
        // 加入事件队列
        enqueueInboundEventLocked(newEntry);
        // 唤醒在mLooper上等待的线程
        mLooper->wake();
    }
    
    void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
        // ...
            
        // 实例化MotionEntry
        MotionEntry* newEntry = new MotionEntry(...);
        // 加入事件队列
        enqueueInboundEventLocked(newEntry);
        // 唤醒在mLooper上等待的线程
        mLooper->wake();
    }
    
    bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
        // 加入队列尾部
        mInboundQueue.enqueueAtTail(entry);
        // ...
    }
    

    可以看到,InputDispatcher#notifyKey()InputDispatcher#notifyMotion()基本类似,都是将事件KeyEntryMotionEntry加入队列mInboundQueue尾部,随后唤醒在mLooperLooper.h)上等待的线程。

    Timethreads图 - 03

    记得我们熟知的生产者-消费者模型吗?

    到这里,我们就完整地在InputReaderThread线程中执行了一次loopOnce(),总结一下关键点:

    • InputReaderEventHub中读取事件,其中一部分是输入事件,我们关心的是按键事件触点事件
    • 事件最终被加入mInboundQueue队列,随即唤醒在mLooper上等待的线程

    那么,唤醒的是哪个线程呢?会不会就是InputDispatcherThread线程呢?相关代码如下:

    // /frameworks/native/services/inputflinger/InputDispatcher.cpp
    
    // --- InputDispatcherThread ---
    
    InputDispatcherThread::InputDispatcherThread(...) {
        bool InputDispatcherThread::threadLoop() {
            mDispatcher->dispatchOnce();
            return true;
        }
    }
    // --- InputDispatcher ---
    
    InputDispatcher::InputDispatcher(...){
        mLooper = new Looper(false);
    }
    
    void InputDispatcher::dispatchOnce() {
        nsecs_t nextWakeupTime = LONG_LONG_MAX;
        // ...
        // 分发一次事件
        dispatchOnceInnerLocked(&nextWakeupTime);
        // ...
        nsecs_t currentTime = now();
        int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
        // 在mLooper上等待一段时间
        mLooper->pollOnce(timeoutMillis);
    }
    
    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
        // ...
        // 获取mInboundQueue队列头部的事件
        mPendingEvent = mInboundQueue.dequeueAtHead();
            
        //...
            
        switch (mPendingEvent->type) {
            // ...
            case EventEntry::TYPE_KEY: {
                    // ...
                    // 分发按键事件
                    done = dispatchKeyLocked(...);
                    break;
            }
            case EventEntry::TYPE_MOTION: {
                    // ...
                    // 分发触点事件
                    done = dispatchMotionLocked(...);
                    break;
            }
        }
        // ...
    }
    

    可以看出,InputDispatcherThread线程中死循环运行dispatchOnce(),每一次都从mInboundQueue队列中获取头部的事件,并执行一次事件分发。每分发一次事件后都会调用mLooper->pollOnce()等待一段时间。等待的过程中,可能被InputReaderThread线程中执行的mLooper.wake()提前唤醒,从而触发下一次事件分发。

    到这里,我们就完整分析了InputManagerService的事件采集流程,关于随后的事件分发过程,我们在后续的文章中继续分析。


    延伸阅读

    • [Android | 系统启动过程]
    • [Android | InputManagerService与输入事件分发]

    推荐阅读


    感谢喜欢!你的点赞是对我最大的鼓励!有任何疑问都可以在下方评论区留言哦!

    相关文章

      网友评论

        本文标题:Android | InputManagerService与输入

        本文链接:https://www.haomeiwen.com/subject/xuelrctx.html