zoukankan      html  css  js  c++  java
  • Android10_原理机制系列_事件传递机制

    前言和概述

    Android的输入设备,最常用的就是 触摸屏和按键 了。当然还有其他方式,比如游戏手柄,比如支持OTG设备,则可以链接鼠标、键盘等。
    那么这些设备的操作 是如何传递到系统 并 控制界面的呢?系统如何知道是如何知道点击了某个界面按钮,按了某个按键,知道交给哪个应用处理的?
    该篇主要介绍这些,即 输入事件从生成(存于设备节点中) 传递到目标View的过程。 在进入输入事件传递机制之前,首先了解一个东西---设备节点。

    了解设备节点

    当有输入事件时,Linux内核会将事件数据写入 设备节点 中,供上层读取最终传递到具体的View中。 该备节点 位于/dev/input/。

    1. 查看:输入事件相关设备信息

    与事件相关的设备信息位于:/proc/bus/input/devices。
    下面是一部分,大致了解下。Name对应的Handlers注意下。

    //查看所有事件相关设备信息
    $ adb shell cat /proc/bus/input/devices
        I: Bus=0019 Vendor=0000 Product=0000 Version=0000
        N: Name="ACCDET"
        P: Phys=
        S: Sysfs=/devices/virtual/input/input0
        U: Uniq=
        H: Handlers=event0
        B: PROP=0
        B: EV=23
        B: KEY=40 0 0 0 0 0 0 0 0 0 0 0 0 10 0 c0000 0 0 0
        B: SW=d4
    
        I: Bus=0019 Vendor=2454 Product=6500 Version=0010
        N: Name="mtk-kpd"
        P: Phys=
        S: Sysfs=/devices/platform/10010000.kp/input/input1
        U: Uniq=
        H: Handlers=event1
        B: PROP=0
        B: EV=3
        B: KEY=1000000 0 0 0 0 0 0 0 0 1c0000 0 0 0
        ...
    

    2. 命令:getevent 和 sendenvent

    2.1 getevent

    通过设备的getevent命令,可以查看输入事件的信息。

    //获取输入事件,这里是按了下电源键
    $ adb shell getevent
        add device 1: /dev/input/event0
          name:     "ACCDET"
        add device 2: /dev/input/event2
          name:     "sf-keys"
        add device 3: /dev/input/event3
          name:     "mtk-tpd"
        add device 4: /dev/input/event1
          name:     "mtk-kpd"
        /dev/input/event1: 0001 0074 00000001
        /dev/input/event1: 0000 0000 00000000
        /dev/input/event1: 0001 0074 00000000
        /dev/input/event1: 0000 0000 00000000
    
    //从/proc/bus/input/devices获取到要关注的设备的节点,可以单独获取
    //下面是获取也是按的电源键获取到的
    $ adb shell getevent  /dev/input/event1
        0001 0074 00000001
        0000 0000 00000000
        0001 0074 00000000
        0000 0000 00000000
    
    //多了解参数,这个-l就很清楚了
    //-l: label event types and names in plain text
    $ adb shell getevent -l /dev/input/event1
        EV_KEY       KEY_POWER            DOWN
        EV_SYN       SYN_REPORT           00000000
        EV_KEY       KEY_POWER            UP
        EV_SYN       SYN_REPORT           00000000
    

    上面列出的3种,第一种没有参数 获取所有输入事件。加上 -l参数 的结果就很清晰了。
    事件类型: 0001 即 EV_KEY,按键
    事件代码: 0074 即 KEY_POWER,电源键
    事件的值: 00000001 即 DOWN,按下;00000000 即 UP,抬起。

    /dev/input/event1: 0001 0074 00000001 就是 电源键按下了。
    /dev/input/event1: 0001 0074 00000000 就是 电源键抬起了。

    注意:这里的值 都是 16进制的。

    触摸屏幕也一样:

    //触摸屏幕截取
    /dev/input/event3: EV_ABS       ABS_MT_TOUCH_MAJOR   0000001e
    /dev/input/event3: EV_ABS       ABS_MT_TRACKING_ID   00000000
    /dev/input/event3: EV_ABS       ABS_MT_POSITION_X    000001b5
    /dev/input/event3: EV_ABS       ABS_MT_POSITION_Y    000001e1
    /dev/input/event3: EV_SYN       SYN_MT_REPORT        00000000
    /dev/input/event3: EV_SYN       SYN_REPORT           00000000
    

    2.2 sendenvent

    输入事件 设备节点也是可写的,通过sendevent可模拟用户输入。
    sendevent 的参数是 十进制。

    格式:sendevent <设备节点> <事件类型> <事件代码> <事件的值>

    所以getevent中,电源按下/抬起的:事件类型即1,事件代码即116,事件的值即1/0。

    //电源键按下
    $ adb shell sendevent /dev/input/event1 1 116 1
    //电源键抬起
    $ adb shell sendevent /dev/input/event1 1 116 0
    //由上述getevent个人理解,0 0 0上报后生效,同按一次电源键操作
    $ adb shell sendevent /dev/input/event1 0 0 0
    

    概述

    该篇也是基于Android10的代码分析。 该篇写时后期调整过几次标题编号,如果文中有参考的编号不对应,请指出。下面图片由于博客显示不是原图,可能部分不清晰,可以单独查看图片原图。
    文章很长,但分的3个模块比较清晰,可以根据需要查看。
    好,这里正式开始了。


    下面是画的一张图,即本章的大致内容。也是方便自己查阅,主要介绍了 输入事件是如何从 设备节点中 传递到具体的View的。

    整篇文章比较长,需要耐心。事件传递的过程 与 WMS关系比较密切,若有需要可以先参考:Android10_原理机制系列_Activity窗口添加到WMS过程Android10_原理机制系列_Window介绍及WMS的启动过程。

    若有不对,欢迎指出:

    wms_ims

    说明:

    • 图中3个红色虚线框: 即下面输入事件传递 介绍的3部分内容。IMS中事件的读取和派发;WMS中Window获取事件和传递;View中事件的传递和处理。
    • 图中2种颜色区域: 标识2个进程。system_server 和 应用进程。
    • 图中红色实线箭头: 文章介绍的 事件传递的 主要过程。
    • 图中2个红色虚线箭头: 列出了 两个比较常见的policy拦截的大致阶段 (当然不止这两个),说明了最终如何回调到PhoneWindowManager的同名方法。

    输入事件的传递

    输入事件的传递过程,如概述中所述,这里分成了3个部分来说明。

    • IMS中事件的读取和派发
    • WMS中Window获取事件和传递
    • View中事件的传递和处理

    下面来具体看看。

    1. IMS中事件的读取和派发

    我们从IMS(InputManagerService)的创建和启动开始看。

    IMS是在SystemServer的 startOtherServices() 方法中启动。(之前总结了AMS/PMS/WMS等,这里类似)

    //SystemServer.java
    private void startOtherServices() {
        WindowManagerService wm = null;
        InputManagerService inputManager = null;
        try {
            //参考1.1,创建IMS对象
            inputManager = new InputManagerService(context);
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
            //注册服务:"input"
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            //参考1.4,设置回调
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            //参考1.5, 启动
            inputManager.start();
        }
        final InputManagerService inputManagerF = inputManager;
        mActivityManagerService.systemReady(() -> {
            try {
                if (inputManagerF != null) {
                    inputManagerF.systemRunning();
                }
            }
        }, BOOT_TIMINGS_TRACE_LOG);
    }
    

    SystemServer中 关于IMS主要看3个内容:

    • new InputManagerService(),最后进入native 最终创建了InputManager及一系列相关内容。
    • inputManager.setWindowManagerCallbacks(),设置了回调,这里说明了 最终如何回调到PhoneWindowManager。
    • inputManager.start(),主要是IntputManager中两个线程运行起来。InputReaderThread读取和处理,InputDispatcherThread派发。

    1.1 创建了InputManager

    先看IMS的构造方法:

    //InputManagerService.java
    public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
        private static native long nativeInit(InputManagerService service,
            Context context, MessageQueue messageQueue);
        
        public InputManagerService(Context context) {
            this.mContext = context;
            //创建了InputManagerHandler,其Looper是DisplayThead的Looper
            this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
            //进入native,并返回了mPtr
            mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
            LocalServices.addService(InputManagerInternal.class, new LocalService());
        }
        
        private final class InputManagerHandler extends Handler {
            public InputManagerHandler(Looper looper) {
                super(looper, null, true /*async*/);
            }
        }
    }
    

    看到 this.mHandler 的Looper 是 DisplayThread的Looper。 这个Looper的消息队列 作为参数 传入到 nativeInit() 方法中。关于Looper,如果不太了解,也可以参考:Android10_原理机制系列_Android消息机制(Handler)详述

    下面进入 nativeInit() 。

    //com_android_server_input_InputManagerService.cpp
    static const JNINativeMethod gInputManagerMethods[] = {
        /* name, signature, funcPtr */
        { "nativeInit",
         "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J",
          (void*) nativeInit },
    }
    
    static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
            jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
        sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        ...
        //创建NativeInputManager
        NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
                messageQueue->getLooper());
        //system/core/libutils/RefBase.cpp查看
        im->incStrong(0);
        //返回给IMS,IMS后续会用到。IMS保存在mPtr。
        return reinterpret_cast<jlong>(im);
    }
    
    //com_android_server_input_InputManagerService.cpp
    //NativeInputManager的构造方法:
    NativeInputManager::NativeInputManager(jobject contextObj,
            jobject serviceObj, const sp<Looper>& looper) :
            mLooper(looper), mInteractive(true) {
        //创建InputManager
        mInputManager = new InputManager(this, this);
        defaultServiceManager()->addService(String16("inputflinger"),
                mInputManager, false);
    }
    

    这里看到,nativeInit() 中创建NativeInputManager。 返回给IMS的是 reinterpret_cast<jlong>(im) ,这是某种转换,可以看作是将NativeInputManager返回给了java层。

    NativeInputManager中又创建了 InputManager。接着看InputManager的创建:

    //InputManager.cpp
    InputManager::InputManager(
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        //创建InputDispatcher
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        mClassifier = new InputClassifier(mDispatcher);
        //创建InputReader
        mReader = createInputReader(readerPolicy, mClassifier);
        //创建了两个线程 InputReaderThread和InputDispatcherThread
        initialize();
    }
    
    void InputManager::initialize() {
        mReaderThread = new InputReaderThread(mReader);
        mDispatcherThread = new InputDispatcherThread(mDispatcher);
    }
    
    //InputReaderFactory.cpp
    sp<InputReaderInterface> createInputReader(
            const sp<InputReaderPolicyInterface>& policy,
            const sp<InputListenerInterface>& listener) {
        //EventHub作为参数 传入InputReader
        return new InputReader(new EventHub(), policy, listener);
    }
    

    上述代码,可以看到,InputManager中基本都是创建操作,创建了InputDispatcher、InputClassifier、InputReader、EventHub、InputReaderThread、InputDispatcherThread。

    下面会逐步看到他们的作用 以及如何运行的。 这里先简单说明下其中几个主要的部分, 先有个大致了解。

    • EventHub:创建InputReader时 可以看到先创建了EventHub作为参数。

      EventHub 通过Linux内核的INotify与Epoll机制 监听设备,可直接访问 设备节点。通过 getEvents() 方法 读取设备节点的原始输入事件 数据。

      关于 EventHub的创建 这里不讨论了,这里只需简单了解它上面一点就可以了。它涉及内核和一些机制,暂时我也还不熟悉,哈哈。

    • InputReader:负责输入事件的获取。在独立线程(InputReaderThread)中 循环执行,有以下几个功能:

      功能1-通过 EventHub 不断 获取设备节点的 原始输入数据

      功能2-然后 进行加工处理后 交由 InputDispatcher分派

      功能3-它还有 管理 输入设备列表和配置

    • InputDispatcher:负责输入事件的派发。在独立线程(InputDispatcherThread)中运行,其保存有WMS的所有窗口信息。

      在接收到 InputReader 的输入事件后,会在窗口信息中找到合适的 窗口 并 派发消息。

    • InputReaderThread、InputDispatcherThread:因为InputReader 和 InputDispatcher都是耗时操作,因此创建 单独线程 来运行他们。这就是他们运行的线程。

    创建完成后,他们是如何联系 并 运行的?

    这个下面从 InputReaderThread和InputDispatcherThread两个线程的运行起来 理一下就可以大致了解。

    1.2 InputReaderThread的运行:InputReader读取和处理事件

    这里从InputReaderThread的运行开始介绍。

    关于InputReaderThread和InputDispatcherThread 是如何运行起来,如何执行的threadLoop() ,后面也介绍了,请参考1.5

    1.2.1 InputReader 获取输入事件

    这里从 InputReaderThread::threadLoop() 开始跟踪:

    //InputReaderBase.cpp
    bool InputReaderThread::threadLoop() {
        mReader->loopOnce();
        return true;
    }
    
    //InputReader.cpp
    void InputReader::loopOnce() {
        ...
        //获取事件
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
        { // acquire lock
            AutoMutex _l(mLock);
            mReaderIsAliveCondition.broadcast();
            if (count) {
                //处理输入事件,参考1.2.2
                processEventsLocked(mEventBuffer, count);
            }
            ...
        } // 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.
        //将事件 推送给 InputDispatcher 进行处理。参考1.2.2.3
        mQueuedListener->flush();
        ...
    }
    

    线程 运行起来后,会执行threadLoop,这里返回true,会循环执行该threadLoop方法。

    threadLoop中调用 loopOnce,通过3步将消息 发送到InputDispatcher:

    • 通过 mEventHub->getEvents()获取所有 输入事件的原始数据。 这部分该篇不讨论
    • 通过 processEventsLocked() 处理输入事件。 参考1.2.2
    • 通过 mQueuedListener->flush() 推送到InputDispatcher。 参考1.2.2.3

    1.2.2 InputReader 处理输入事件

    看下处理输入事件的方法:processEventsLocked()

    //InputReader.cpp
    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;
                }
                //处理 真正的输入事件,参考 1.2.2.2
                processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
            } else {
                //处理 设备增加、删除、扫描更新。参考1.2.2.1
                switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                ...
                }
            }
            count -= batchSize;
            rawEvent += batchSize;
        }
    }
    

    前面讲了InputReader有3个功能,这里可以看到功能2和3:对输入事件进行加工处理后 交由InputDispatcher;对输入设备 列表的管理和配置。先看功能3,在看功能2。

    1.2.2.1 了解输入设备的管理

    先看下功能3:对输入设备 列表的管理和配置。

    这里以增加设备 为例,看下addDeviceLocked():

    //InputReader.cpp
    void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
        if (deviceIndex >= 0) {
            ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
            return;
        }
        InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
        uint32_t classes = mEventHub->getDeviceClasses(deviceId);
        int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
        //创建InputDevice
        InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
        device->configure(when, &mConfig, 0);
        device->reset(when);
        ...
    	//加入mDevices
        mDevices.add(deviceId, device);
        ...
    }
    
    //mDevices 和 InputDevice定义(截取部分)
    //InputReader.h
    class InputReader : public InputReaderInterface {
    	KeyedVector<int32_t, InputDevice*> mDevices;
    }
    class InputDevice {
    	int32_t mId;//通过mId从EventHub中找到对应的输入设备
    	std::vector<InputMapper*> mMappers;//处理上报的事件
    }
    

    这里创建了一个InputDevice,然后将其加入到mDevices。mDevices 中保存了 设备的id 以及 对应的InputDevice。

    EventHub 中也有个 mDevices,保存了 设备的id 和 对应的Device信息。 如下(截取部分):

    //EventHub.h
    class EventHub : public EventHubInterface {
        KeyedVector<int32_t, Device*> mDevices;
        
        struct Device {
            Device* next;
            int fd; // may be -1 if device is closed  //设备节点 的文件句柄
            const int32_t id;
            const std::string path;
            const InputDeviceIdentifier identifier; //记录设备信息,设备的名称、供应商、型号等等
            std::unique_ptr<TouchVideoDevice> videoDevice;
            uint32_t classes;
    		std::unique_ptr<VirtualKeyMap> virtualKeyMap;
            KeyMap keyMap;
    	}
    }
    

    看下 创建InputDevice的过程,createDeviceLocked():

    //InputReader.cpp
    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);
    
        // External devices.
        if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
            device->setExternal(true);
        }
        // Keyboard-like devices.
        ...
        if (keyboardSource != 0) {
            device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
        }
        // 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));
        }
        return device;
    }
    
    void InputDevice::addMapper(InputMapper* mapper) {
        mMappers.push_back(mapper);
    }
    

    创建了InputDevice后,进行一些设置。值得关注的是 一个InputDevice保存了多个 InputMapper,这些InputMapper保存在mMappers。

    简单理一下:InputReader添加设备,首先创建了一个InputDevice,然后加入到mDevices中。而根据设备类型,可以创建多个InputMapper,这多个InputMapper保存在InputDevice中的mMappers中。

    1.2.2.2 输入事件处理

    接着看功能2,对输入事件进行处理 processEventsForDeviceLocked() :

    //InputReader.cpp
    void InputReader::processEventsForDeviceLocked(int32_t deviceId,
            const RawEvent* rawEvents, size_t count) {
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
        //最终根据deviceId获得设备对应的InputDevice
        InputDevice* device = mDevices.valueAt(deviceIndex);
        //事件交由 对应InputDevice处理。rawEvents是一组事件,可以注意下来源。                       
        device->process(rawEvents, count);
    }
    
    //InputReader.cpp
    void InputDevice::process(const RawEvent* rawEvents, size_t count) {
        // Process all of the events in order for each mapper.
        // We cannot simply ask each mapper to process them in bulk because mappers may
        // have side-effects that must be interleaved.  For example, joystick movement events and
        // gamepad button presses are handled by different mappers but they should be dispatched
        // in the order received.
        for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
            ...
            if (mDropUntilNextSync) {
                if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                    mDropUntilNextSync = false;
                    ...
                } 
                ...
            } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
                ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
                mDropUntilNextSync = true;
                reset(rawEvent->when);
            } else {
    			//将InputDvices对象中的mMappers依次取出来,调用process()进行处理
                for (InputMapper* mapper : mMappers) {
                    mapper->process(rawEvent);
                }
            }
            --count;
        }
    }
    

    InputReader 获得某设备相关一组事件,然后找到对应InputDevice进行处理,执行 InputDevice::process()

    InputDevice则将InputDvices对象中的mMappers依次取出来,调用process()进行处理。各个 InputMapper 对事件进行判断,若是属于自己处理的类型 再进行不同的处理。

    下面 以键盘事件 为例说明,则InputMapper是KeyboardInputMapper:

    //InputReader.cpp
    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)) {
                    //处理事件,这里即处理按键的方法
                    processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
                }
                break;
            }
            ...
        }
    }
    
    //InputReader.cpp
    //内核上报的扫描码(scanCode),转换成Android系统使用的按键码(keyCode),重构NotifyArgs,加入 mArgsQueue队列
    void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
            int32_t usageCode) {
        int32_t keyCode;
        int32_t keyMetaState;
        uint32_t policyFlags;
        ...
        //重构args
        NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
                getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
        //插入到 mArgsQueue 队列中
        getListener()->notifyKey(&args);
    }
    

    这个处理过程 主要是 封装各个参数,重新构造成 NotifyKeyArgs ,然后 将构造的 NotifyKeyArgs对象加入 mArgsQueue队列。

    加入到 mArgsQueue的过程, getListener()->notifyKey(&args):

    //InputReader.cpp
    InputListenerInterface* InputReader::ContextImpl::getListener() {
        return mReader->mQueuedListener.get();
    }
    InputReader::InputReader(const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& policy,
            const sp<InputListenerInterface>& listener) : ... {
        mQueuedListener = new QueuedInputListener(listener);
    }
    
    //InputListener.cpp
    QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
            mInnerListener(innerListener) {
    }
    void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
        mArgsQueue.push_back(new NotifyKeyArgs(*args));//push_back() 在Vector尾部插入
    }
    //InputListener.h
    class QueuedInputListener : public InputListenerInterface {
        std::vector<NotifyArgs*> mArgsQueue;
    };
    

    在1.1中 创建InputReader时已经知道(可以回去看下),InputReader中的lister是InputClassifier对象,所以 QueuedInputListener中的innerListener 也就是 InputClassifier。

    到这里再理一下:事件先交由了对应的InputDevice,然后找对处理该事件类型的InputMapper 进行处理。InputMapper 将事件等信息 构造了NotifyArgs,然后加入到了mArgsQueue中。

    1.2.2.3 输入事件传入到 InputDispatcher

    看 InputReader::loopOnce() 的最后一句:mQueuedListener->flush();

    //InputListener.cpp
    void QueuedInputListener::flush() {
        size_t count = mArgsQueue.size();
        //依次从mArgsQueue中取出NotifyArgs
        for (size_t i = 0; i < count; i++) {
            NotifyArgs* args = mArgsQueue[i];
            //mInnerListener是InputClassifier,上面(1.2.2.2最后)已经特意指出
            args->notify(mInnerListener);
            delete args;
        }
        mArgsQueue.clear();
    }
    
    

    如注释所说。接着看 args->notif(),接下来都是以键盘事件为例:

    //NotifyArgs是所有args的超类。 以键盘为例,args即NotifyKeyArgs
    void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
        listener->notifyKey(this);
    }
    
    
    //InputManager.cpp
    InputManager::InputManager(
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        mClassifier = new InputClassifier(mDispatcher);
    }
    //InputClassifier.cpp
    //mListener是InputDispatcher
    InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener)
          : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
    
    
    void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
        // pass through
        mListener->notifyKey(args);
    }
    

    很清楚列出了,这里的mListener即InputDispatcher。所以最终走到了 InputDispatcher::notifyKey():

    //InputDispatcher.cpp
    void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
        ...
        int32_t keyCode = args->keyCode;
        //Meta + Backspace -> generate BACK; Meta + Enter -> generate HOME
        accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
    
        KeyEvent event;
        event.initialize(args->deviceId, args->source, args->displayId, args->action,
                flags, keyCode, args->scanCode, metaState, repeatCount,
                args->downTime, args->eventTime);
    
        android::base::Timer t;
        //mPolicy是NativeInputManager,最终回调到PhoneWindowManager的同名方法。参考1.2.2.4
        mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
        ...
        bool needWake;
        { // acquire lock
            mLock.lock();
            ...
            KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime,
                    args->deviceId, args->source, args->displayId, policyFlags,
                    args->action, flags, keyCode, args->scanCode,
                    metaState, repeatCount, args->downTime);
    
            needWake = enqueueInboundEventLocked(newEntry);
            mLock.unlock();
        } // release lock
    
        if (needWake) {
            mLooper->wake();
        }
    }
    
    bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
        bool needWake = mInboundQueue.isEmpty();
        //entry加入到mInboundQueue
        mInboundQueue.enqueueAtTail(entry);
        ...
        return needWake;
    }
    

    最终,输入事件 由InputReader 获取处理后,传递到InputDispatcher,封装成EventEntry并加入mInboundQueue 队列了。

    1.2.2.4 事件入队前的拦截:interceptKeyBeforeQueueing()

    注意上面 InputDispatcher::notifyKey 中有 mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); 这句话,对PhoneWindowManager有过了解的,应该比较清楚。

    这里就是 policy拦截的 比较常见的一处,从这最终回调 的是 PhoneWindowManager中的方法。

    这个大致看下,这里mPolicy即 NativeInputManager ,所以直接看NativeInputManager::interceptKeyBeforeQueueing()

    //com_android_server_input_InputManagerService.cpp
    void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
            uint32_t& policyFlags) {
        ...
    	wmActions = env->CallIntMethod(mServiceObj,
                        gServiceClassInfo.interceptKeyBeforeQueueing,
                        keyEventObj, policyFlags);
        ...
    }
    //InputManagerService.java
    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
    }
    

    这个跟踪 就是执行了IMS中的interceptKeyBeforeQueueing()方法。

    最终是如何调用到 PhoneWindowManager 中的方法的?

    这里的mWindowManagerCallbacks是 wms中创建的InputManagerCallback对象。这个如何来的 参考1.4。

    所以 mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 即:

    //InputManagerCallback.java
    public InputManagerCallback(WindowManagerService service) {
        mService = service;
    }
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
    }
    

    这里的mService.mPolicy就是PhoneWindowManager对象,在WMS创建时设置的。所以最终 回调的 PhoneWindowManager 中的 interceptKeyBeforeQueueing() 方法。 PhoneWindowManager 是 WindowManagerPolicy 的实现类。

    1.3 InputDispatcherThread运行:InputDispatcher派发事件

    前面讲到,输入事件 在InputDispatcher中 封装成EventEntry并加入mInboundQueue 队列了。接着看 InputDispatcher是如何继续处理 派发的。
    如同InputReaderThread中介绍,这里直接看threadLoop()。

    //frameworks/native/services/inputflinger/InputDispatcher.cpp
    bool InputDispatcherThread::threadLoop() {
        mDispatcher->dispatchOnce();
        return true;
    }
    
    void InputDispatcher::dispatchOnce() {
        nsecs_t nextWakeupTime = LONG_LONG_MAX;
        { // acquire lock
            std::scoped_lock _l(mLock);
            mDispatcherIsAlive.notify_all();
    
            // Run a dispatch loop if there are no pending commands.
            // The dispatch loop might enqueue commands to run afterwards.
            //若mCommandQueue为空
            if (!haveCommandsLocked()) {
                //参考1.3.1
                dispatchOnceInnerLocked(&nextWakeupTime);
            }
    
            // Run all pending commands if there are any.
            // If any commands were run then force the next poll to wake up immediately.
            //参考1.3.4,运行 mCommandQueue 中命令
            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);
    }
    
    //InputDispatcher.h
    EventEntry* mPendingEvent GUARDED_BY(mLock);
    Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
    Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
    Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
    
    //InputDispatcher.cpp
    bool InputDispatcher::haveCommandsLocked() const {
        return !mCommandQueue.isEmpty();
    }
    

    1.3.1 InputDispatcher 取得输入事件

    1.2.2.3讲到:输入事件 由InputReader 获取处理后,加入到了InputDispatcher中的 mInboundQueue 队列了。

    事件派发 首先从 mInboundQueue队列中 取出输入事件,然后进行处理。

    //InputDispatcher.cpp
    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
        ...
        // Ready to start a new event.
        // If we don't already have a pending event, go grab one.
        if (! mPendingEvent) {
            if (mInboundQueue.isEmpty()) {
                ...
            } else {
                // Inbound queue has at least one entry.
                //从mInboundQueue中 出队 一个元素
                mPendingEvent = mInboundQueue.dequeueAtHead();
                traceInboundQueueLengthLocked();
            }
    
            // Poke user activity for this event.
            if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
                pokeUserActivityLocked(mPendingEvent);
            }
    
            // Get ready to dispatch the event.
            //这里注意下,ANR相关。这里先mark下,这篇不说明
            resetANRTimeoutsLocked();
        }
    
        // Now we have an event to dispatch.
        // All events are eventually dequeued and processed this way, even if we intend to drop them.
        ...
    
        switch (mPendingEvent->type) {
        ...
        case EventEntry::TYPE_KEY: {
            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
            ...
            //分派事件
            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
        ...
    }
    

    取出事件后,然后分派,这里同样以 键盘按键事件为例,直接看 dispatchKeyLocked():

    1.3.2 分派事件前处理

    直接看 dispatchKeyLocked():

    //InputDispatcher.cpp
    bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
            DropReason* dropReason, nsecs_t* nextWakeupTime) {
        ...
    
        // Give the policy a chance to intercept the key.
        if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
            //派发给用户,参考1.3.2.1
            if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
                //将InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible函数指针作为参数
                //执行postCommandLocked(),执行后 该函数被封装到CommandEntry 加入到 mCommandQueue队列
                CommandEntry* commandEntry = postCommandLocked(
                        & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
                //InputWindowHandle保存了窗口相关信息,由java层而来
                //获取焦点窗口的InputWindowHandle
                sp<InputWindowHandle> focusedWindowHandle =
                        getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
                if (focusedWindowHandle != nullptr) {
                    //InputChannel也是一种跨进程
                    commandEntry->inputChannel =
                        getInputChannelLocked(focusedWindowHandle->getToken());
                }
                commandEntry->keyEntry = entry;
                entry->refCount += 1;
                return false; // wait for the command to run
            } else {
                entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
            }
        } 
        ...
        
        // Identify targets.
        //参考 1.3.2.3 
        std::vector<InputTarget> inputTargets;
        int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
        ...
        // Add monitor channels from event's or focused display.
        addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
    
        // Dispatch the key.
        //参考1.3.3
        dispatchEvenfentLocked(currentTime, entry, inputTargets);
        return true;
    }
    
    InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
        CommandEntry* commandEntry = new CommandEntry(command);
        mCommandQueue.enqueueAtTail(commandEntry);
        return commandEntry;
    }
    
    1.3.2.1 事件分派前的拦截:interceptKeyBeforeDispatching()

    通过postCommandLocked() 将 doInterceptKeyBeforeDispatchingLockedInterruptible 函数作为参数,封装到CommandEntry 最后加入到 mCommandQueue队列。这个函数并没有马上运行。

    这个doInterceptKeyBeforeDispatchingLockedInterruptible():

    //InputDispatcher.cpp
    void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
            CommandEntry* commandEntry) {
        KeyEntry* entry = commandEntry->keyEntry;
        ...
        sp<IBinder> token = commandEntry->inputChannel != nullptr ?
            commandEntry->inputChannel->getToken() : nullptr;
        nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token,
                &event, entry->policyFlags);
        ...
        entry->release();
    }
    

    interceptKeyBeforeDispatching() 类似1.2.2.4。最终也是 调用到PhoneWindowManager 中的同名方法。

    1.3.2.2 了解InputWindowHandle和InputChannel

    InputWindowHandle:

    InputWindowHandle保存了窗口相关信息,由java层而来。

    关于InputWindowHandle 知道这大概是什么,不影响此篇理解,就没有完全跟踪下去。下面个人查看的路径开始,内容挺多,也没跟踪完全。先记录下,后续再看。

    //WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq, ...) {
        displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
    }
    
    //InputMonitor.java
    /* Updates the cached window information provided to the input dispatcher. */
    void updateInputWindowsLw(boolean force) {
        if (!force && !mUpdateInputWindowsNeeded) {
            return;
        }
        scheduleUpdateInputWindows();
    }
    

    InputChannel:

    InputChannel也是一种跨进程, 本质也是socket。是一对创建的。

    WindowState创建了一对InputChannel。server端注册到InputDispatcher,建立了Connect。client端返回给应用进程的窗口,ViewRootImpl.setView()时传入的参数mInputChannel。

    InputDispatcher向其InputChannel中写入事件,窗口就可以从InputChannel中读取了。

    简单列出下相关代码:

    //WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState) {
        final boolean openInputChannels = (outInputChannel != null
                && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
        if  (openInputChannels) {
            //outInputChannel来自 ViewRootImpl.setView()时创建的
            win.openInputChannel(outInputChannel);
        }
    }
    
    //WindowState.java
    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        //创建一对InputChannel,创建过程该篇不说明。         
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        mInputWindowHandle.token = mClient.asBinder();
        if (outInputChannel != null) {
            //mClientChannel传递给 outInputChannel
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        //mInputChannel注册到了InputDispatcher,注册过程也不说明了。           
        mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
    }
    
    //InputDispatcher.cpp
    status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
            int32_t displayId) {
        { // acquire lock
            sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
            int fd = inputChannel->getFd();
            mConnectionsByFd.add(fd, connection);
            mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
            mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
        } // release lock
    }
    
    1.3.2.3 确认目标

    直接看 findFocusedWindowTargetsLocked() :

    //InputDispatcher.cpp
    int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
            const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
        int32_t injectionResult;
        std::string reason;
        int32_t displayId = getTargetDisplayId(entry);
        sp<InputWindowHandle> focusedWindowHandle =
                getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
        sp<InputApplicationHandle> focusedApplicationHandle =
                getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
        ...
        // Success!  Output targets.
        injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
        addWindowTargetLocked(focusedWindowHandle,
                InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
                inputTargets);
        ...
        return injectionResult;
    }
    
    void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
            int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) {
        sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
        if (inputChannel == nullptr) {
            ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
            return;
        }
        const InputWindowInfo* windowInfo = windowHandle->getInfo();
        InputTarget target;
        target.inputChannel = inputChannel;
        target.flags = targetFlags;
        target.xOffset = - windowInfo->frameLeft;
        target.yOffset = - windowInfo->frameTop;
        target.globalScaleFactor = windowInfo->globalScaleFactor;
        target.windowXScale = windowInfo->windowXScale;
        target.windowYScale = windowInfo->windowYScale;
        target.pointerIds = pointerIds;
        inputTargets.push_back(target);
    }
    

    找到目标的InputWindowHandle,生成一个InputTarget 然后加入到inputTargets中。

    InputTarget包含了窗口的各种信息,如上可以仔细看下。

    1.3.3 分派事件

    直接看 dispatchEventLocked(),。

    //InputDispatcher.cpp
    void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
            EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
        ATRACE_CALL();
        ...
        pokeUserActivityLocked(eventEntry);
    
        for (const InputTarget& inputTarget : inputTargets) {
            ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
            if (connectionIndex >= 0) {
                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
            }
            ...
        }
    }
    
    void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
            const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
        ...
        // Not splitting.  Enqueue dispatch entries for the event as is.
        enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
    }
    

    循环取出inputTargets的目标,一个个处理:

    //InputDispatcher.cpp
    void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
            const sp<Connection>& 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::enqueueDispatchEntryLocked(
            const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
            int32_t dispatchMode) {
        ...
        DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
                inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
                inputTarget->globalScaleFactor, inputTarget->windowXScale,
                inputTarget->windowYScale);
        ...
        // Enqueue the dispatch entry.
        connection->outboundQueue.enqueueAtTail(dispatchEntry);
        traceOutboundQueueLength(connection);
    
    }
    

    Connection个人理解是一个通道。Connection中有一个outboundQueue队列,上面将符合的事件封装为DispatchEntry放到Connection的outboundQueue队列中了。

    然后接着看分派周期 startDispatchCycleLocked():

    //InputDispatcher.cpp
    void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
            const sp<Connection>& connection) {
        ...
        while (connection->status == Connection::STATUS_NORMAL
                && !connection->outboundQueue.isEmpty()) {
            //从connection的outboundQueue队列取出一个元素
            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<KeyEntry*>(eventEntry);
    
                // Publish the key event.
                //派发按键事件
                status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                        keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
                        dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                        keyEntry->keyCode, keyEntry->scanCode,
                        keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                        keyEntry->eventTime);
                break;
            }
            ...
            // Re-enqueue the event on the wait queue.
            connection->outboundQueue.dequeue(dispatchEntry);
            traceOutboundQueueLength(connection);
            connection->waitQueue.enqueueAtTail(dispatchEntry);
            traceWaitQueueLength(connection);
        }
    }
    
    //InputTransport.cpp
    InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
            mChannel(channel) {
    }
    status_t InputPublisher::publishKeyEvent(
           ...) {
        ...
        InputMessage msg;
        msg.header.type = InputMessage::TYPE_KEY;
        msg.body.key.seq = seq;
        msg.body.key.deviceId = deviceId;
        msg.body.key.source = source;
        msg.body.key.displayId = displayId;
        msg.body.key.action = action;
        msg.body.key.flags = flags;
        msg.body.key.keyCode = keyCode;
        msg.body.key.scanCode = scanCode;
        msg.body.key.metaState = metaState;
        msg.body.key.repeatCount = repeatCount;
        msg.body.key.downTime = downTime;
        msg.body.key.eventTime = eventTime;
        //通过InputChannel发送消息
        return mChannel->sendMessage(&msg);
    }
    

    循环取出Connection中outboundQueue队列中的 事件依次处理分派。这里还是 以按键 为例,通过 inputPublisher.publishKeyEvent() 分派了事件,即 最终是 将事件等信息 封装为InputMessage, 通过InputChannel将 这个消息发送出去。

    //InputTransport.cpp
    status_t InputChannel::sendMessage(const InputMessage* msg) {
        const size_t msgLength = msg->size();
        InputMessage cleanMsg;
        msg->getSanitizedCopy(&cleanMsg);
        ssize_t nWrite;
        do {
            //
            nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
        } while (nWrite == -1 && errno == EINTR);
        ...
        return OK;
    }
    

    1.3.4 分派事件后 执行挂起命令

    在InputDispatcher::dispatchOnce()中 ,前面讲到的事件分派 都是 dispatchOnceInnerLocked()的执行,这个是 没有挂起命令情况下执行的(即mCommandQueue为空)。

    如果mCommandQueue非空,则会执行挂起的命令。如 在1.3.2.1中 拦截命令 被封装 加入了mCommandQueue 队列,然后分派就结束了。

    如果mCommandQueue非空,会执行其中的命令,即 runCommandsLockedInterruptible() :

    //InputDispatcher.cpp
    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;
    }
    

    1.4 设置回调:setWindowManagerCallbacks

    在startOtherServices()中,创建了InputManagerService后,执行了 inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback()); 。这个就是设置的回调(即设置了mWindowManagerCallbacks),与前面提到的 两个拦截有关,1.2.2.4已经说的比较明白了。这里主要其中mWindowManagerCallbacks是什么。

    这句话很简单,直接看下:

    //WindowManagerService.java 
    final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);
    public InputManagerCallback getInputManagerCallback() {
        return mInputManagerCallback;
    }
    
    //InputManagerService.java
    public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
        mWindowManagerCallbacks = callbacks;
    }
    

    这里的 mWindowManagerCallbacks 就是 wm.getInputManagerCallback(),即 创建的InputManagerCallback对象。

    1.5 启动:start()

    前面 InputReader读取事件 和 InputDispatcher分派事件,这个过程是在 InputReaderThread和InputDispatcherThread 两个线程运行起来,执行了 threadLoop() 基础上讲解的。

    那么 这两个线程是如何 运行起来,执行 threadLoop() 的?下面就来看下。

    1.5.1 进入native

    在 startOtherServices()中,创建IMS后,设置了回调,最后有 inputManager.start(); ,这个就是 两个线程运行起来 并执行了 threadLoop() 的起点。

    //InputManagerService.java
    private static native void nativeStart(long ptr);
    
    public void start() {
        ...
        nativeStart(mPtr);
        ...
    }
    

    这里主要看下 nativeStart() 这个方法。 在 上面部分1.1 创建 InputManagerService中,大家还记得 mPtr 是:通过nativeInit()进入native创建 NativeInputManager 后的相关返回值(mPtr 是 reinterpret_cast(im),某一种转换)。

    继续跟踪下去。

    //com_android_server_input_InputManagerService.cpp
    static const JNINativeMethod gInputManagerMethods[] = {
        { "nativeStart", "(J)V", (void*) nativeStart },
    }
    
    static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
        //mPtr又转换成了NativeInputManager
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
        status_t result = im->getInputManager()->start();
        ...
    }
    

    mPtr又转换成了NativeInputManager,然后调用了InputManager的 start()方法。 继续看:

    1.5.2 run() 操作

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

    来看,这里就是 InputReaderThread 和 InputDispatcherThread 两个线程 执行了 run() 操作。 具体看下这个run() 做了些啥,需要看其父类Thread。

    1.5.3 创建线程 并 执行 threadLoop()

    //system/core/libutils/Threads.cpp
    Thread::Thread(bool canCallJava)
        : mCanCallJava(canCallJava),
          ...
    {
    }
    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
        Mutex::Autolock _l(mLock);
        ...
        bool res;
     	//InputReaderThread 和 InputDispatcherThread 创建时传入的 为true。
        if (mCanCallJava) {
            //创建线程。 注意这里的 _threadLoop
            res = createThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        } else {
            res = androidCreateRawThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        }
        ...
        return OK;
    }
    
    //frameworks/native/services/inputflinger/InputReaderBase.cpp
    InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
            Thread(/*canCallJava*/ true), mReader(reader) {
    }
    //frameworks/native/services/inputflinger/InputDispatcher.cpp
    InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
            Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
    }
    

    这里,mCanCallJava 是 true(创建 InputReaderThread和InputDispatcherThread时 传入的,上面代码也列出),然后通过createThreadEtc() 即创建 线程。 注意其中有个参数 _threadLoop。下面是 _threadLoop。

    //system/core/libutils/Threads.cpp
    int Thread::_threadLoop(void* user)
    {
        Thread* const self = static_cast<Thread*>(user);
        ...
        result = self->threadLoop();
        ...
        return 0;
    }
    

    这里 就是 执行 自身的 threadLoop(),即 InputReaderThread 和 InputDispatcherThread 两线程 执行 threadLoop()。

    2. WMS中Window获取事件和传递

    IMS端讲完了,我们知道最后消息通过InputChannel发送到目标窗口的进程了。接下来看目标窗口是如何接收传递的。

    首先,来看下ViewRootImpl.setView() :

    //ViewRootImpl.java
    InputQueue.Callback mInputQueueCallback;
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ...
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    //创建InputChannel对象 mInputChannel
                    mInputChannel = new InputChannel();
                }
                mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                try {
                    ...
                    //这里主要关注mInputChannel,它就是前面讲到的一个InputChannel,wms创建一对后传递回来的
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
                    setFrame(mTmpFrame);
                } 
                ...
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    //创建WindowInputEventReceiver,这里的Looper是应用主线程的Looper
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ...
            }
        }
    }
    

    前面也提到过,这里创建的mInputChannel 最终作为参数传递到WMS中,此时它什么都没有。在 WMS.addWindow()中 WindowState创建了一对InputChannel,其中一个通过transferTo()传递给了 mInputChannel。接下来就看WindowInputEventReceiver的创建。

    2.1 WindowInputEventReceiver 的创建

    //ViewRootImpl.java
    final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
    }
    
    //InputEventReceiver.java
    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        ...
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);
    
        mCloseGuard.open("dispose");
    }
    

    通过nativeInit() 进入 native层:

    //android_view_InputEventReceiver.cpp
    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
            jobject inputChannelObj, jobject messageQueueObj) {
        ...
        //参考2.2,创建NativeInputEventReceiver
        sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
                receiverWeak, inputChannel, messageQueue);
        //参考2.3,执行initialize
        status_t status = receiver->initialize();
        ...
        receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
        return reinterpret_cast<jlong>(receiver.get());
    }
    

    2.2 创建NativeInputEventReceiver

    //android_view_InputEventReceiver.cpp
    class NativeInputEventReceiver : public LooperCallback {
    NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
            jobject receiverWeak, const sp<InputChannel>& inputChannel,
            const sp<MessageQueue>& messageQueue) :
            mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
            mInputConsumer(inputChannel), mMessageQueue(messageQueue),
            mBatchedInputEventPending(false), mFdEvents(0) {
        ...
    }
    
    InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
            mResampleTouch(isTouchResamplingEnabled()),
            mChannel(channel), mMsgDeferred(false) {
    }
    

    创建NativeInputEventReceiver,注意两个地方 后面会讲到的:

    • inputChannel封装到mInputConsumer
    • NativeInputEventReceiver是LooperCallback的派生类,实现了handleEvent()方法。

    2.3 执行initialize()

    //android_view_InputEventReceiver.cpp
    status_t NativeInputEventReceiver::initialize() {
        setFdEvents(ALOOPER_EVENT_INPUT);
        return OK;
    }
    
    void NativeInputEventReceiver::setFdEvents(int events) {
        if (mFdEvents != events) {
            mFdEvents = events;
            
            int fd = mInputConsumer.getChannel()->getFd();
            if (events) { 
                //fd添加到Looper中,监听InputChannel 读取事件
                mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
            } else {
                mMessageQueue->getLooper()->removeFd(fd);
            }
        }
    }
    
    /**
    * The file descriptor is available for read operations.
    */
    ALOOPER_EVENT_INPUT = 1 << 0,
    

    addFd()参数this是LooperCallback,即NativeInputEventReceiver。
    跟踪下,fd最终添加到Looper的mRequests列表中。

    当Looper监听到有输入事件时,会回调 NativeInputEventReceiver的handleEvent()方法。 (这里面的机制也还没细究)

    这个可以参考下:Looper::pollInner()中 int callbackResult = response.request.callback->handleEvent(fd, events, data);

    2.4 回调handleEvent()

    //android_view_InputEventReceiver.cpp
    int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
        ...
        if (events & ALOOPER_EVENT_INPUT) {
            JNIEnv* env = AndroidRuntime::getJNIEnv();
            //获取事件,然后回调到java层的 InputEventReceiver.dispatchInputEvent
            status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
        }
        ...
        return 1;
    }
    
    //android_view_InputEventReceiver.cpp
    status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
            bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
        ...
        ScopedLocalRef<jobject> receiverObj(env, NULL);
        bool skipCallbacks = false;
        for (;;) {
            uint32_t seq;
            InputEvent* inputEvent;
            //从InputChannel读取信息,并处理保存事件到inputEvent,参考2.4.1
            status_t status = mInputConsumer.consume(&mInputEventFactory,
                    consumeBatches, frameTime, &seq, &inputEvent);
            ...
            if (!skipCallbacks) {
                ...
                if (inputEventObj) {
                    ...
                    //回调java层的 InputEventReceiver.dispatchInputEvent,参考2.4.2
                    env->CallVoidMethod(receiverObj.get(),
                            gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                } 
            }
            ...
        }
    }
    
    //jni注册:android_view_InputEventReceiver.cpp
    int register_android_view_InputEventReceiver(JNIEnv* env) {
        int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver",
                gMethods, NELEM(gMethods));
        jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver");
        gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
        gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env,
                gInputEventReceiverClassInfo.clazz,
                "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
        gInputEventReceiverClassInfo.dispatchBatchedInputEventPending = GetMethodIDOrDie(env,
                gInputEventReceiverClassInfo.clazz, "dispatchBatchedInputEventPending", "()V");
        return res;
    }
    

    NativeInputEventReceiver::handleEvent() 到 NativeInputEventReceiver::consumeEvents()。这里关注两个:

    • 从InputChannel读取信息,并处理保存事件到inputEvent
    • 回调java层的 InputEventReceiver.dispatchInputEvent

    2.4.1 从InputChannel读取事件

    //InputTransport.cpp
    status_t InputConsumer::consume(InputEventFactoryInterface* factory,
            bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
        ...
        *outSeq = 0;
        *outEvent = nullptr;
    
        // Fetch the next input message.
        // Loop until an event can be returned or no additional events are received.
        while (!*outEvent) {
            //前面列出过InputConsumer创建时 mMsgDeferred为false
            if (mMsgDeferred) {
                ...
            } else {
                // Receive a fresh message.
                //mChannel接收消息,即从socket中读取
                status_t result = mChannel->receiveMessage(&mMsg);
                ...
            }
            ...
        }
        switch (mMsg.header.type) {
            case InputMessage::TYPE_KEY: {
                ...
                initializeKeyEvent(keyEvent, &mMsg);
                *outSeq = mMsg.body.key.seq;
                *outEvent = keyEvent;
                break;
            }
    
            case InputMessage::TYPE_MOTION: {
                ...
                updateTouchState(mMsg);
                initializeMotionEvent(motionEvent, &mMsg);
                *outSeq = mMsg.body.motion.seq;
                *outEvent = motionEvent;
                break;
            }
        }
        return OK;
    }
    
    

    通过InputChannel接受IMS端发送过来的消息,并且根据事件类型做了一些处理。

    2.4.2 回调java层的 InputEventReceiver.dispatchInputEvent

    //InputEventReceiver.java
    @UnsupportedAppUsage
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }
    

    前面知道,创建的是InputEventReceiver的子类WindowInputEventReceiver,因此onInputEvent()调用的是子类中方法:

    //ViewRootImpl.java
    final class WindowInputEventReceiver extends InputEventReceiver {
        @Override
        public void onInputEvent(InputEvent event) {
            ...
            if (processedEvents != null) {
                ...
            } else {
                //输入事件 加入队列
                enqueueInputEvent(event, this, 0, true);
            }
        }
    }
    

    2.5 输入事件处理

    这里继续看 enqueueInputEvent():

    //ViewRootImpl.java
    @UnsupportedAppUsage
    void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        //获取QueuedInputEvent,event等封装进去。
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        //获取队尾
        QueuedInputEvent last = mPendingInputEventTail;
        //插入队尾
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        //数目加1
        mPendingInputEventCount += 1;
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);
        //是否立即执行
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }
    

    enqueueInputEvent() 首先将event等信息封装到了QueuedInputEvent,然后将其插入输入事件队列的队尾。

    继续看doProcessInputEvents():

    //ViewRootImpl.java
    void doProcessInputEvents() {
        // Deliver all pending input events in the queue.
        while (mPendingInputEventHead != null) {
            QueuedInputEvent q = mPendingInputEventHead;
            ...
            deliverInputEvent(q);
        }
    }       
    

    循环处理队列中所有事件,每次取队首元素 传递处理。交由deliverInputEvent()方法处理。

    2.6 输入事件 传递到View

    继续看deliverInputEvent():

    //ViewRootImpl.java
    private void deliverInputEvent(QueuedInputEvent q) {
        ...
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }
    
        if (q.mEvent instanceof KeyEvent) {
            mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
        }
    
        if (stage != null) {
            handleWindowFocusChanged();
            //传递,参考3.1
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        // Set up the input pipeline.
        CharSequence counterSuffix = attrs.getTitle();
        mSyntheticInputStage = new SyntheticInputStage();
        InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
        InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                "aq:native-post-ime:" + counterSuffix);
        InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
        InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                "aq:ime:" + counterSuffix);
        InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
        InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                "aq:native-pre-ime:" + counterSuffix);
    
        mFirstInputStage = nativePreImeStage;
        mFirstPostImeInputStage = earlyPostImeStage;
        mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
    }
    

    在setView() 中,创建了 input pipeline,将事件一层层传递下去。 调用stage.deliver(q); 传递下去。

    3. 事件在View中的传递

    前面讲到 事件已经传递到input pipeline中。这个暂不细究,往下继续看传递到View中的传递。

    3.1 传递到DecorView

    直接看 stage.deliver(q) :

    //ViewRootImpl.java
    abstract class InputStage {
        public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                apply(q, onProcess(q));
            }
        }
    }
    

    onProcess(q)返回一个处理结果,apply根据这个结果再决定是否传递到InputStage的下一层。

    这主要关注的 onProcess()。在ViewPostImeInputStage阶段,开始向DecorView传递。

    //ViewRootImpl.java
    final class ViewPostImeInputStage extends InputStage {
        @Override
        protected int onProcess(QueuedInputEvent q) {
            //处理不同类型的事件
            if (q.mEvent instanceof KeyEvent) {
                //按键事件处理
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }
        
        private int processKeyEvent(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;
            ...
            // Deliver the key to the view hierarchy.
            if (mView.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
            }
            ...
            return FORWARD;
        }
    }
    

    onProcess()中对不同类型事件进行不同的处理。这里仍然以按键事件为例,处理方法processKeyEvent()。

    这个mView即DecorView,setView()时 传入的。

    为什么是DecorView? 这个过程请参考: Android10_原理机制系列_Activity窗口添加到WMS过程。


    3.2 传递到Activity

    //DecorView.java
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        final int keyCode = event.getKeyCode();
        final int action = event.getAction();
        final boolean isDown = action == KeyEvent.ACTION_DOWN;
        ...
        if (!mWindow.isDestroyed()) {
            final Window.Callback cb = mWindow.getCallback();
            final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
                    : super.dispatchKeyEvent(event);
            if (handled) {
                return true;
            }
        }
        return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
                : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
    }
    

    如果是Activity的窗口,cb获取到的是Activity,mFeatureId是-1。这里的mWindow是PhoneWindow,即Activity在attach()时 创建的PhoneWindow,在setContentView()过程 通过mDecor.setWindow()传入到DecorView中的。

    这个mWindow.getCallback()获取的是Activity本身,即Activity在attach()时setCallback() 传入的this本身。

    这个过程请参考( 那篇窗口添加到WMS中 说的很明白,这里不列出了): Android10_原理机制系列_Activity窗口添加到WMS过程。


    3.3 事件在View中传递处理

    由于按键事件 和 触摸事件是 最常见的,这里都简单列举了下。

    3.3.1 按键事件传递处理

    接着前面,按键事件 可以直接看cb.dispatchKeyEvent(event):

    //Activity.java
    public boolean dispatchKeyEvent(KeyEvent event) {
        ...
        Window win = getWindow();
        //交由Window继续传递,返回false,则继续交由Activity处理。若返回的true,则下层已处理掉了。          
        if (win.superDispatchKeyEvent(event)) {
            return true;
        }
        View decor = mDecor;
        if (decor == null) decor = win.getDecorView();
        return event.dispatch(this, decor != null
                ? decor.getKeyDispatcherState() : null, this);
    }
    //PhoneWindow.java
    @Override
    public boolean superDispatchKeyEvent(KeyEvent event) {
        //传递给DecorView
        return mDecor.superDispatchKeyEvent(event);
    }
    //DecorView.java
    public boolean superDispatchKeyEvent(KeyEvent event) {
        ...
        //传递到ViewGroup。返回true,则下层处理了 上层不处理。  
        if (super.dispatchKeyEvent(event)) {
            return true;
        }
    
        return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
    }
    //ViewGroup.java
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
            //传递给具体的View
            if (super.dispatchKeyEvent(event)) {
                return true;
            }
        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
                == PFLAG_HAS_BOUNDS) {
            if (mFocused.dispatchKeyEvent(event)) {
                return true;
            }
        }
        return false;
    }
    //View.java
    public boolean dispatchKeyEvent(KeyEvent event) {
        ...
        // Give any attached key listener a first crack at the event.
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
            return true;
        }
        if (event.dispatch(this, mAttachInfo != null
                           ? mAttachInfo.mKeyDispatchState : null, this)) {
            return true;
        }
        return false;
    }
    //KeyEvent.java
    public final boolean dispatch(Callback receiver, DispatcherState state,
    		Object target) {
    	switch (mAction) {
    		case ACTION_DOWN: {
    			mFlags &= ~FLAG_START_TRACKING;
    			boolean res = receiver.onKeyDown(mKeyCode, this);
    			...
    			return res;
    		}
    		case ACTION_UP:
    			...
    			return receiver.onKeyUp(mKeyCode, this);
    		case ACTION_MULTIPLE:
    			...
    			return false;
    	}
    	return false;
    }
    

    由上述代码过程,keyEvent由外到内传递,由Activity到具体的View。

    ListenerInfo就是关联的我们自定义的监听,如setOnClickListener(),setOnLongClickListener。

    这里的传递是:由Activity到ViewGrop再到View,如果某个环节返回true,即事件被处理掉不再向下层传递。如果最底层View仍未处理 而返回false,则再依次向外传递至Activity(向外传递中仍未被处理的话)处理。

    注意:dispatchKeyEvent()都是有的。 onKeyDown,onKeyUp、onKeyLongPress等是View中有,同样为true即处理掉 不在传递了。

    3.3.2 触摸事件传递处理

    触摸事件,类似按键事件,这里直接看 最终传递到的Activity的地方。

    //Activity.java
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        //传递到Window
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        //若下层不处理,则调用onTouchEvent()处理掉。
        return onTouchEvent(ev);
    }
    //PhoneWindow.java
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
    //DecorView.java
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }
    //ViewGroup.java
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        ...
        boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) {
            ...
            // Check for interception.
            final boolean intercepted;
            ...
                	//拦截
                    intercepted = onInterceptTouchEvent(ev);
            ...
            
            if (intercepted || mFirstTouchTarget != null) {
                ev.setTargetAccessibilityFocus(false);
            }
            //Update list of touch targets for pointer down, if needed.
            if (!canceled && !intercepted) {
                ...
            }
    
            // Dispatch to touch targets.
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            } else {
    				...
                            if (dispatchTransformedTouchEvent(ev, cancelChild,
                                    target.child, target.pointerIdBits)) {
                                handled = true;
                            }
            }
        }
        return handled;
    }
    
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        ...
        // Perform any necessary transformations and dispatch.
        if (child == null) {
            handled = super.dispatchTouchEvent(transformedEvent);
        } else {
            ...
            handled = child.dispatchTouchEvent(transformedEvent);
        }
        return handled;
    }
    //View.java
    public boolean dispatchTouchEvent(MotionEvent event) {
        ...
        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
    
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
    
        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        ...
        return result;
    }
    

    与按键事件类似,由外到内传递。也有ListenerInfo关联View中自定义的监听。

    传递过程也基本一样:由Activity到ViewGrop再到View,如果某个环节返回true,即事件被处理掉不再向下层传递。如果最底层View仍未处理 而返回false,则再依次向外传递至Activity(向外传递中仍未被处理)处理。

    注意:dispatchTouchEvent(),onTouchEvent()都是有的。 ViewGroup中多了个onInterceptTouchEvent(),若为true, 则是将事件拦截,不在传递。


    到此结束了,本篇差不多有上万字了,但也只是个大概。仍需不断学习。
    多谢阅读,欢迎交流。


  • 相关阅读:
    《团队-Android手机便签-项目进度》
    《结对-结对编项目作业名称-测试过程》
    《结对-结对编项目作业名称-开发过程》
    ios auto layout demystified (二)
    ios auto layout demystified (一)
    电子书下载地址
    轻应用、Web app 、Native app三者区别关系是什么?
    ios录制测试
    Understanding apps: mobile, native or responsive
    iOS开发工具——网络封包分析工具Charles
  • 原文地址:https://www.cnblogs.com/fanglongxiang/p/14091511.html
Copyright © 2011-2022 走看看