从源码角度看InputManagerService

简介

上篇文章《从源码角度看Activity显示视图流程》中,我从Activity被成功创建开始分析,到 ViewRootImpl 进行控件树的绘制,最后再到 ViewRootImpl 与 WMS 的通信。这期间其实涉及到了 InputManagerService 的一些初始化工作,里面 InputChannel 初始化的代码我都没有继续深入分析

这篇文章里,我将系统的分析 IMS 的源码,照惯例先放出一张整体的类图与流程图,方便把握整体。最后分了三个小节分别去介绍其中的细节

文章将会分析到 InputEventReceive.onInputEvent 方法,这个方法是客户端事件分发机制的入口,下片文章里我将从 onInputEvent 为入口开始分析

查看大图

整体流程图

查看大图

  1. 用户轻点屏幕,linux 内核产生中断,向 /dev/input/ 目录下的设备文件 eventxx 下入数据
  2. native 层,EventHub 通过 epoll 监测到文件被写入,使用 inotify 读取文件中的数据
  3. InputReader 将事件数据解析成装满 RawEvent 的缓冲区中,随后批量使用 InputMapper 进行处理
  4. 用户的触摸事件最终被加工为 NotifyMotionArgs,随后被批量插入到 InputDispatcher 的队列中
  5. InputDispacher 从队列中取出 EventEntry 数据进行派发
  6. 获取触摸事件目标窗口列表,使用 socketpair 向客户端发送输入事件
  7. 客户端在将事件分发到各个窗口,处理完毕后会调用 finish 告诉服务端事件已经处理完成
  8. InputDispatcher 收到事件处理完成通知,重新初始化 ANR 相关变量

IMS 初始化与启动

InputManagerService 读取事件数据、解析并派发事件到客户端的逻辑都是在 native 实现的,java 层所做的工作不过是接收并反馈事件处理的结果

这一节对应着整体流程的初始化步骤,如epoll 与 inotify 对于输入事件设备文件的初始化,有了它们 android 才得以以高效的方式获取用户输入事件的数据;如InputReaderThread 和 InputDispatcherThread 两个重要线程,才使得整个 ims 服务的工作流程犹如工厂生产线一般前后贯通

查看大图

初始化 epoll 与 inotify

frameworks/base/services/java/com/android/server/SystemServer.java

1
2
3
4
5
6
7
8
private void startOtherServices() {
...
Slog.i(TAG, "Input Manager");
inputManager = new InputManagerService(context);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
inputManager.start();
...
}

和WMS, AMS 这些重要系统服务一样,IMS也是在SystemServer.startOtherServices中进行初始化,并调用 start 方法启动

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

1
2
3
public InputManagerService(Context context) {
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}

InputManagerService 中,直接调用 nativeInit 在 native 中进行初始化

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
...
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}

初始化 EventHub 与 InputManager,其中 EventHub 的本质要封装了 epoll 与 inotify,监听设备写入的事件并读取到缓冲中进行简单解析

frameworks/native/services/inputflinger/EventHub.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
// 新建一个 epoll
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
// 初始化 inotify
mINotifyFd = inotify_init();
// 监听设备的创建与删除
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
DEVICE_PATH, errno);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 增加需要监听的设备 fd
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
...
}

epoll 初始化完成后,当输入设备被写入数据后,epoll_wait 就会返回数据,并可以对其进行解析

启动 IMS

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

1
2
3
4
5
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
...
}

调用 native 方法,启动 InputDispatcherThread 与 InputReaderThread 两个重要线程

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
7
8
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}

通过 JNI 调用到 native 后,调用 InputManager 的 start 方法启动 IMS 服务

frameworks/native/services/inputflinger/InputManager.cpp

1
2
3
4
5
6
7
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
return OK;
}

可以看到,InputManager 只是启动了两个 native 线程,循环来处理输入事件的数据

frameworks/native/services/inputflinger/InputReader.cpp

1
2
3
4
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}

frameworks/native/services/inputflinger/InputDispatcher.cpp

1
2
3
4
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}

以上,通过两个线程不断调用 loopOnce 与 dispatchOnce,IMS 的基本服务已经初始化完毕,接下来进入正题,从 InputReader 读取输入设备事件开始分析 IMS 是如何一步一步的将设备中的数据分发到用户能看到的视图中的

一些背景知识

  • 内核中断: 当触屏驱动被挂载到对应的 /dev/input/event0 后,触摸屏幕会导致触摸屏的引脚电平变低,随后CPU引脚监测到电压的变化就会产生中断,中断处理程序就会读取触屏的数据
  • inotify: 实现 /dev/input 目录文件状态的监听
  • epoll: I/O 多路复用机制,使用 epoll_ctl 函数进行注册监听 inotify 的文件句柄,当事件到来时会采用类似回调的方式执行回调方法

输入事件的读取与解析

查看大图

当 epoll, inotify 与两个线程被初始化,当事件到来时,InputReader 便会率先开始工作。这一节中,IuputReader 会从 EventHub 中读取数据,随后会交给对应的 InputMapper 将事件的类型进行加工。加工完毕后会将事件数据批量的插入到 InputDispatcher 的队列中以供派发

InputReader.loopOnce:InputReaderThread 的一次读取

frameworks/native/services/inputflinger/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void InputReader::loopOnce() {
...
// 从 EventHub 中读取数据
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 如果有数据则进行处理
processEventsLocked(mEventBuffer, count);
}
...
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
...
// 讲添加进缓存队列中的事件一齐插入到 InputDispatcher 的队列中
mQueuedListener->flush();
}

这段代码基本可以概括 InputReader 的主要职责,逻辑很清晰。其中 EventHub.getEvents 如果获取到了数据才会进行到下一个状态中,大部分时间里,如果没有输入事件 getEvents 将会产生阻塞,不会消耗 CPU 资源

EventHub.getEvents:IMS 的心跳

frameworks/native/services/inputflinger/EventHub.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
// 事件的获取不是一个一个的获取,而是采用缓冲队列的形式,分批去获取的
RawEvent* event = buffer;
for (;;) {
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
// 读取 mPendingEventItems 中的设备数据
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
for (size_t i = 0; i < count; i++) {
// 封装成 input_event
struct input_event& iev = readBuffer[i];
...
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
}
...
// epoll 监测到设备可读
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}
return event - buffer;

InputReader.processEventsLocked: 预处理输入事件

以上的代码是个大致的逻辑,当通过 epoll 获取到可读设备的 fd 后,下一个循环将会读取设备中的数据

frameworks/native/services/inputflinger/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
...
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
count -= batchSize;
rawEvent += batchSize;
}
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
...
device->process(rawEvents, count);
}

可以看到获取到的事件数据是委托给 InputDevice 调用 process 方法来进行处理的

frameworks/native/services/inputflinger/InputReader.cpp#InputDevice

1
2
3
4
5
6
7
8
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
...
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
void TouchInputMapper::process(const RawEvent* rawEvent) {
...
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
void TouchInputMapper::sync(nsecs_t when) {
const RawState* last = mRawStatesPending.isEmpty() ?
&mCurrentRawState : &mRawStatesPending.top();
...
processRawTouches(false /*timeout*/);
}
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
...
dispatchPointerUsage(when, policyFlags, pointerUsage);
...
}
void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags,
PointerUsage pointerUsage) {
...
switch (mPointerUsage) {
case POINTER_USAGE_STYLUS:
dispatchPointerStylus(when, policyFlags);
break;
default:
break;
}
}
void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) {
...
dispatchPointerSimple(when, policyFlags, down, hovering);
}
void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
bool down, bool hovering) {
...
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
// Send up.
// 将事件封装成 NotifyMotionArgs,随后调用 QueuedInputListener 接口插入到缓存队列中
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
getListener()->notifyMotion(&args);
}
...
}

这一步事件的处理逻辑很复杂,我不准备详细分析了。我这边列出的是精简的关于触摸类型的事件处理,只需记得事件处理完成后,最后的输出结果是将封装好的 NotifyMotionArgs 插入到 QueuedInputListener 队列中即可

frameworks/native/services/inputflinger/InputListener.cpp#QueuedInputListener

1
2
3
4
5
6
7
8
9
10
11
12
13
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}

可以看到, 调用notifyXXX系列方法最终都是插入到名为 mArgsQueue 的队列中。当缓冲队列中的所有事件都处理完毕之后,InputReader 会调用 flush 批量将队列中的事件进行 notify

QueuedInputListener.notify:插入到 InputDispatcher 队列

frameworks/native/services/inputflinger/InputListener.cpp#QueuedInputListener

1
2
3
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}

以触摸事件为例,notify实际上调用的是 listener 的notifyMotion,而 listener 对象实际是 InputDispatcher 的一个引用,所以最终调用的还是 InputDispatcher 的notifyMotion方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
...
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
bool needWake;
{ // acquire lock
mLock.lock();
...
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
...
}

最终会将 NotifyMotionArgs 事件插入到 InputDispatcher 的 mInboundQueue 队列中。到这里 InputReader 的 loopOnce 就结束了,正如方法名阐述的,进行一个输入设备的数据读取,至于后面的事件派发工作就交给 InputDispatcher 来处理了

输入事件的派发

InputDispatcher.dispatchOnce

frameworks/native/services/inputflinger/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
...
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
...
} // 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);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
...
} else {
mPendingEvent = mInboundQueue.dequeueAtHead();
}
}
...
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
...
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
}
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
Vector<InputTarget> inputTargets;
...
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
dispatchEventLocked(currentTime, entry, inputTargets);
}

这段代码的逻辑是讲触屏的事件数据进行分发处理。期间省略掉了许多操作,其中包括在 findTouchedWindowTargetsLocked 对 ANR 的判断 ,如果监测到派发的时间超过了 5s 还没有处理完成的话,native 就会通知 java 层需要触发 ANR

findTouchedWindowTargetsLocked 同时会找到事件作用的客户端并保存在 inputTargets 列表中

frameworks/native/services/inputflinger/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
...
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
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) {
...
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
...
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
...
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
...
}

最终通过获取到的 Connection,调用 InputPublishser 的publishMotionEvent 方法将事件传输到客户端,这里看一下 Connection 的实现,其实就是封装了 InputChannel 成员变量与 window 句柄的类

1
2
3
4
5
6
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
monitor(monitor),
inputPublisher(inputChannel), inputPublisherBlocked(false) {
}

在分析 InputChannel 发送消息到客户端,传输数据事件之前,先看看 InputChannel 的初始化

InputChannel 服务端的初始化

上一篇文章《从源码角度看Activity显示视图流程》分析视图的显示层看到过 WindowManager.addWindow 的方法,其实在视图进行显示时,也正是发送 Input 事件的 InputChannel 进行初始化的时机

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
...
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
...
}

openInputChannelPair 会调用 native 方法初始化 socketpair,registerInputChannel 则是将 inputChannel 句柄传入 native 给 InputDispatcher

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
...
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
...
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}

frameworks/native/services/inputflinger/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
...
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
...
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}

regsiterInputChannel 最终的操作是初始化一个 Connection,将引用传给它并添加到 mConnectionByFd 队列中,可以根据 socketpair 的fd来查询

InputPublisher.publishMotionEvent

frameworks/native/libs/input/InputTransport.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
status_t InputPublisher::publishMotionEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
float xOffset,
float yOffset,
float xPrecision,
float yPrecision,
nsecs_t downTime,
nsecs_t eventTime,
uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
InputMessage msg;
msg.header.type = InputMessage::TYPE_MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
return mChannel->sendMessage(&msg);
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
...
}

通过将信息封装成 InputMessage,随后使用 InputChannel.sendMessage 将信息发送到客户端

InputChannel 客户端的初始化

frameworks/base/core/java/android/view/ViewRootImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
}
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
}

ViewRootImpl.setView 时,与WMS 通信完成之后会去初始化 InputChannel 的客户端

frameworks/base/core/java/android/view/InputEventReceiver.java

1
2
3
4
5
6
7
8
9
10
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
...
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}

通过调用 nativeInit 在 native 层进行初始化

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
...
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
...
return reinterpret_cast<jlong>(receiver.get());
}
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) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}

真正的实现是在 NativeInputEventReceiver.initialize 方法进行的,最终使用的是传入的 MessageQueue 中的 Looper 来监听 InputChannel 客户端的 fd 实现的,本质上还是使用了 epoll 机制来监听 fd 的可读状态。当事件到来时,会调用回调方法 handleEvent 来处理事件

输入事件的处理与反馈

查看大图

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
...
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
...
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
for (;;) {
env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
}
...
mInputConsumer.sendFinishedSignal(seq, false);
}

当事件到来时,handleEvent 会调用 java 方法,通知上层继续处理输入事件,当事件处理完成之后会调用 sendFinishedSignal 通过服务端事件处理已经完成

frameworks/base/core/java/android/view/InputEventReceiver.java

1
2
3
public void onInputEvent(InputEvent event) {
finishInputEvent(event, false);
}

此处是 java 层收到输入事件的入口,后续的文章会分析 View 的事件派发机制,将会接着这条线继续分析

frameworks/native/libs/input/InputTransport.cpp

1
2
3
4
5
6
7
8
9
10
11
12
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
...
return sendUnchainedFinishedSignal(seq, handled);
}
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
msg.header.type = InputMessage::TYPE_FINISHED;
msg.body.finished.seq = seq;
msg.body.finished.handled = handled;
return mChannel->sendMessage(&msg);
}

将 java 层处理完毕输入事件的信息由客户端发向服务端

frameworks/native/services/inputflinger/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
...
ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
for (;;) {
uint32_t seq;
bool handled;
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
if (status) {
break;
}
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
gotOne = true;
}
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq, bool handled) {
...
onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}

handleReceiveCallback 也是使用 Looper 中的 epoll 机制监听的回调方式,注册的方式和客户端一样,这里就不累述了

总结

InputManagerService 相对于 Android 其它几个大服务来说代码量虽然较少,看起来也没有那么复杂,整个流程从 Input 事件的读取、派发、处理和反馈都井然有序,如同一个生产工厂,虽然庞大但是有秩序,看起来很有条有理。

因为平时我接触 Android 源码部分最多的还是 AMS,看 Android 源码给我的印象就如同阅读一本史诗级的厚书,虽然有分有量但是及其难啃。读 IMS 的过程中,我明显感觉到代码的设计之优雅,虽然整个对输入事件的处理流程很长,但是各个重要模块的封装都十分精致,对缓冲区、设计模式、epoll和socketpair 的运行恰如其分,读的不仅能够学得 Android 事件的流程,其中的代码设计范式也很值得我去学习

扫码支持0.99元,您的支持将鼓励我继续创作!