Android的输入设备,最经常使用的就是 触摸屏和按键 了。固然还有其余方式,好比游戏手柄,好比支持OTG设备,则能够连接鼠标、键盘等。
那么这些设备的操做 是如何传递到系统 并 控制界面的呢?系统如何知道是如何知道点击了某个界面按钮,按了某个按键,知道交给哪一个应用处理的?
该篇主要介绍这些,即 输入事件从生成(存于设备节点中) 传递到目标View的过程。 在进入输入事件传递机制以前,首先了解一个东西---设备节点。
html
当有输入事件时,Linux内核会将事件数据写入 设备节点 中,供上层读取最终传递到具体的View中。 该备节点 位于/dev/input/。java
与事件相关的设备信息位于:/proc/bus/input/devices。
下面是一部分,大体了解下。Name对应的Handlers注意下。android
//查看全部事件相关设备信息 $ 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 ...
经过设备的getevent命令,能够查看输入事件的信息。redis
//获取输入事件,这里是按了下电源键 $ 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,抬起。shell
/dev/input/event1: 0001 0074 00000001 就是 电源键按下了。
/dev/input/event1: 0001 0074 00000000 就是 电源键抬起了。session
注意:这里的值 都是 16进制的。app
触摸屏幕也同样:socket
//触摸屏幕截取 /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
输入事件 设备节点也是可写的,经过sendevent可模拟用户输入。
但 sendevent 的参数是 十进制。async
格式:sendevent <设备节点> <事件类型> <事件代码> <事件的值>ide
因此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的启动过程。
如有不对,欢迎指出:
说明:
输入事件的传递过程,如概述中所述,这里分红了3个部分来讲明。
下面来具体看看。
咱们从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个内容:
先看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两个线程的运行起来 理一下就能够大体了解。
这里从InputReaderThread的运行开始介绍。
关于InputReaderThread和InputDispatcherThread 是如何运行起来,如何执行的threadLoop() ,后面也介绍了,请参考1.5
这里从 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:
看下处理输入事件的方法: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。
先看下功能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中。
接着看功能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中。
看 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 队列了。
注意上面 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 的实现类。
前面讲到,输入事件 在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.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():
直接看 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; }
经过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 中的同名方法。
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 }
直接看 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包含了窗口的各类信息,如上能够仔细看下。
直接看 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; }
在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; }
在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对象。
前面 InputReader读取事件 和 InputDispatcher分派事件,这个过程是在 InputReaderThread和InputDispatcherThread 两个线程运行起来,执行了 threadLoop() 基础上讲解的。
那么 这两个线程是如何 运行起来,执行 threadLoop() 的?下面就来看下。
在 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
继续跟踪下去。
//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()方法。 继续看:
//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。
//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()。
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的建立。
//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()); }
//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,注意两个地方 后面会讲到的:
//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);
。
//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()。这里关注两个:
//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端发送过来的消息,而且根据事件类型作了一些处理。
//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); } } }
这里继续看 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()方法处理。
继续看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);
传递下去。
前面讲到 事件已经传递到input pipeline中。这个暂不细究,往下继续看传递到View中的传递。
直接看 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过程。
//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过程。
因为按键事件 和 触摸事件是 最多见的,这里都简单列举了下。
接着前面,按键事件 能够直接看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即处理掉 不在传递了。
触摸事件,相似按键事件,这里直接看 最终传递到的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, 则是将事件拦截,不在传递。
到此结束了,本篇差很少有上万字了,但也只是个大概。仍需不断学习。
多谢阅读,欢迎交流。