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, 则是将事件拦截,不在传递。


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


posted @ 2020-12-08 01:25  流浪_归家  阅读(1985)  评论(1编辑  收藏  举报