Android输入系统(二)IMS的启动过程和输入事件的处理www.bbx.vip
前言
在上一篇文章中,我们学习了IMS的诞生(创建),IMS创建后还会进行启动,这篇文章我们来学习IMS的启动过程和输入事件的处理。www.bbx.vip
1.IMS的启动过程
IMS的创建在SystemServer的startOtherServices方法中,不了解请查看Android输入系统(一)输入事件传递流程和InputManagerService的诞生这篇文章。
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
…
traceBeginAndSlog(“StartInputManagerService”);
inputManager = new InputManagerService(context);
traceEnd();
…
traceBeginAndSlog(“StartInputManager”);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
}
1
2
3
4
5
6
7
8
9
10
11
12
创建IMS后就会紧接着执行IMS的启动。IMS的start方法如下所示。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void start() {
Slog.i(TAG, “Starting input manager”);
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
…
}
1
2
3
4
5
6
7
IMS的start方法中,会将自身添加到Watchdog中进行监控,用于定时检测系统关键服务(AMS和WMS等)是否可能发生死锁。
nativeStart方法对应的JNI层的函数是什么呢?查看com_android_server_input_InputManagerService的gInputManagerMethods数组,不理解JNI的可以查看深入理解JNI系列文章。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static const JNINativeMethod gInputManagerMethods[] = {
…
{ “nativeStart”, “(J)V”,
(void*) nativeStart },
…
}
1
2
3
4
5
6
nativeStart方法对应的JNI函数为nativeStart:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz /, jlong ptr) {
NativeInputManager im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();//1
if (result) {
jniThrowRuntimeException(env, “Input manager could not be started.”);
}
}
1
2
3
4
5
6
7
用reinterpret_cast操作符将jlong类型的ptr强制转换为原类型(NativeInputManager指针类型)。注释1处会调用InputManager的start函数。
frameworks/native/services/inputflinger/InputManager.cpp
status_t InputManager::start() {
status_t result = mDispatcherThread->run(“InputDispatcher”, PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE(“Could not start InputDispatcher thread due to error %d.”, result);
return result;
}
result = mReaderThread->run(“InputReader”, PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE(“Could not start InputReader thread due to error %d.”, result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
可以看到InputManager的start函数运行了InputReaderThread和InputDispatcherThread,这两个线程在Android输入系统(一)输入事件传递流程和InputManagerService的诞生提到过,它们在InputManager的构造函数中被创建,其中InputReaderThread中运行了InputReader, InputDispatcherThread中运行了InputDispatcher。
2.InputDispatcher的启动过程
先来回顾下InputDispatcher和InputReader是在哪创建的,InputManager的构造函数如下所示。
frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
1
2
3
4
5
6
7
8
可以看到InputDispatcher和InputReader是有关联的,InputDispatcher会作为一个参数传入到InputReader中。
InputDispatcher是在InputReader之前创建的,这个顺序不能改变,因为要确保InputReader将加工后的输入事件交给InputDispatcher时,InputDispatcher已经被创建。
InputDispatcher的定义如下所示。
frameworks/native/services/inputflinger/InputDispatcher.h
class InputDispatcherThread : public Thread {
public:
explicit InputDispatcherThread(const sp& dispatcher);
~InputDispatcherThread();
private:
virtual bool threadLoop();
sp mDispatcher;
};
}
1
2
3
4
5
6
7
8
9
InputDispatcher.h中定义了threadLoop纯虚函数,InputDispatcher继承了Thread。native的Thread内部有一个循环,当线程运行时,会调用threadLoop函数,如果它返回true并且没有调用requestExit函数,就会接着循环调用threadLoop函数。
查看InputDispatcherThread的threadLoop函数是如何实现的。
frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
1
2
3
4
threadLoop函数中只调用了InputDispatcher的dispatchOnce函数:
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
if (!haveCommandsLocked()) {//1
dispatchOnceInnerLocked(&nextWakeupTime);//2
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
nsecs_t currentTime = now();//3
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);//4
mLooper->pollOnce(timeoutMillis);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
注释1处用于检查InputDispatcher的缓存队列中是否有等待处理 的命令,如果没有就会执行注释2处的dispatchOnceInnerLocked函数,用来将输入事件分发给合适的Window。注释3处获取当前的时间,结合注释4处,得出InputDispatcherThread需要睡眠的时间为timeoutMillis。最后调用Looper的pollOnce函数使InputDispatcherThread进入睡眠状态,并将它的最长的睡眠的时间设置为timeoutMillis。当有输入事件产生时,InputReader就会将睡眠状态的InputDispatcher
唤醒,InputDispatcher会重新开始分发输入事件。
那么InputReader是如何唤醒InputDispatcherThread的呢? 我们接着往下看。
3.InputReader处理事件过程
InputReader是在InputReaderThread中启动的,InputReaderThread和InputDispatcherThread的定义是类似的,也是继承了Thread并定义了threadLoop纯虚函数。如果处理的事件为键盘输入事件,则调用时序图如下所示。
InputReaderThread的threadLoop函数如下所示。
frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
1
2
3
4
threadLoop函数中只调用了InputReader的loopOnce函数:
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
…
//通过EventHub的getEvents函数获取事件信息存在mEventBuffer中
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//1
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//如果有事件信息,调用processEventsLocked函数对事件进行加工处理
processEventsLocked(mEventBuffer, count);//2
}
…
}
1
2
3
4
5
6
7
8
9
10
11
12
13
注释1处调用EventHub的getEvents函数来获取设备节点的事件信息到mEventBuffer中,事件信息主要有两种,一种是设备节点的增删事件(设备事件),一种是原始输入事件。注释2处的processEventsLocked函数用于对mEventBuffer中的原始输入事件信息进行加工处理,加工后的输入事件会交由InputDispatcher来处理,processEventsLocked函数如下所示。
frameworks/native/services/inputflinger/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;
}
#if DEBUG_RAW_EVENTS
ALOGD(“BatchSize: %d Count: %d”, batchSize, count);
#endif
//处理deviceId所对应的设备的原始输入事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);//1
} else {
//对设备事件进行处理
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can’t happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
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
InputReader的processEventsLocked函数首先遍历了所有的事件,这些事件用RawEvent对象来表示,将原始
输入事件和设备事件分开处理,其中设备事件分为DEVICE_ADDED、DEVICE_REMOVED和FINISHED_DEVICE_SCAN,这些事件是在EventHub的getEvent函数中生成的。如果是DEVICE_ADDED事件(设备添加事件),InputReader会新建InputDevice对象,用来存储设备信息,并且会将InputDevice存储在
KeyedVector类型的容器mDevices中。
同一个设备的输入事件交给processEventsForDeviceLocked函数来处理。
frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//1
if (deviceIndex < 0) {
ALOGW(“Discarding event for unknown deviceId %d.”, deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);//2
if (device->isIgnored()) {
//ALOGD(“Discarding event for ignored deviceId %d.”, deviceId);
return;
}
device->process(rawEvents, count);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
注释1处根据deviceId从mDevices中获取对应的deviceIndex,注释2处再根据这个deviceIndex从mDevices中获取对应的InputDevice。最后会调用InputDevice的process函数:
www.bbx.vip www.bbx.vip www.bbx.vip www.bbx.vip www.bbx.vip