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的启动过程。
若有不对,欢迎指出:
说明:
- 图中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
继续跟踪下去。
//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, 则是将事件拦截,不在传递。
到此结束了,本篇差不多有上万字了,但也只是个大概。仍需不断学习。
多谢阅读,欢迎交流。