原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處,多謝配合。
上篇簡單交代了下輸入子系統(tǒng),那么這篇主要分析下InputReader獲取事件過程。
一、InputReader初始化
從前面初始化的介紹中,我們知道InputReader是在InputManager構(gòu)造方法中被初始化的。
frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
值得留意的是,InputDispatcher作為參數(shù)傳入了InputReader的構(gòu)造方法。
再看InputReader的構(gòu)造方法:
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);//這個(gè)listener對應(yīng)的就是InputDispatcher
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
InputReader的構(gòu)造函數(shù)中初始化了一個(gè)QueuedInputListener, 它接收InputListenerInterface作為它的參數(shù),從InputReader調(diào)用可知,這個(gè)InputListenerInterface其實(shí)就是InputDispatcher, QueueInputListener只是作為InputDispatcher的Wrapper.這里先埋個(gè)伏筆。
二、InputReader運(yùn)行
在InputManager執(zhí)行start的時(shí)候InputReaderThread->run()
frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
接著執(zhí)行 mReader->loopOnce();
void InputReader::loopOnce() {
…
//獲取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//處理事件
processEventsLocked(mEventBuffer, count);
}
...
//傳遞事件
mQueuedListener->flush();
}
這里主要做了三件事:獲取事件、處理事件、傳遞事件,下面分別來看看:
2.1 獲取事件
EventHub->getEvents上一篇已經(jīng)分析了,主要就是獲取kernel的event, 這里事件不僅包括input,還包括輸入設(shè)備的add/remove等相關(guān)事件。加入的輸入設(shè)備在沒有事件的時(shí)候,會(huì)block在EventHub中的epoll處,當(dāng)有事件產(chǎn)生后,epoll_wait就會(huì)返回,然后針對變化的事件進(jìn)行處理。
2.2 處理事件
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
//1、處理輸入事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED://2、添加輸入設(shè)備
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED://3、刪除輸入設(shè)備
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN://4、完成設(shè)備掃描
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
這里主要處理以上這4類事件,這里重點(diǎn)只關(guān)注下input event的收集流程:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
...
InputDevice* device = mDevices.valueAt(deviceIndex);//獲取到對應(yīng)的device
...
device->process(rawEvents, count);//device執(zhí)行process操作
}
這里看到input的處理流程是由device執(zhí)行process發(fā)起的。
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
...
if (mDropUntilNextSync) {
...
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {//對應(yīng)的EV_KEY type走如下流程
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);//對應(yīng)的InputMapper執(zhí)行process操作
}
}
}
}
這里執(zhí)行的是mapper對應(yīng)的process,而mapper實(shí)際上就是對應(yīng)device中能匹配處理當(dāng)前event的具體執(zhí)行類。
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;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
這里以案件事件EV_KEY為例,這里會(huì)執(zhí)行processKey方法
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
…
//調(diào)用eventhub的mapKey
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {
...
}
...
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);//參數(shù)打包成args發(fā)送給Listener
}
最終將event組合成了一個(gè)notifykeyArgs數(shù)據(jù)結(jié)構(gòu),同時(shí)調(diào)用了listener的notifykey方法。
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
這里將NotifyKeyArgs放入了一個(gè)ArgsQueue中。
這部分簡單來梳理一下:
InputReader收集不同設(shè)備輸入信息,而不同設(shè)備對事件的處理又有分類,因?yàn)榫唧wdevice的具體event交由對應(yīng)的mapper來處理,而不匹配的則忽略。而mapper的處理主要是將event按NotifyArgs數(shù)據(jù)結(jié)構(gòu)進(jìn)行封裝,并加入到一個(gè)ArgsQueue中。而NotifyArgs本身也是按事件類型來封裝的。


2.3 傳遞事件
frameworks/native/services/inputflinger/InputListener.cpp
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();
}
從ArgsQueue把事件取出來,分別調(diào)用它們自己的notify方法
以NotifyKeyArgs為例:
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
這個(gè)listener對應(yīng)的是mInnerListener,那么要想知道Args傳遞到哪去了,就確定下mInnerListener是什么就好了。而在之前的初始化介紹部分已經(jīng)埋過伏筆的,QueuedInputListener(listener);中傳入的這個(gè)listener對應(yīng)的就是InputDispatcher。
frameworks/native/services/inputflinger/InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
所以最終跟代碼發(fā)現(xiàn)innerListener實(shí)際上就是InputDispatcher,notifyKey()就是InputDispacher的成員函數(shù)
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
...
int32_t keyCode = args->keyCode;
...
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime);
…
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
...
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
if (needWake) {
mLooper->wake();//如果需要被喚醒,則喚醒dispatcher對應(yīng)的Looper
}
}
這里重點(diǎn)看兩個(gè)方法:interceptKeyBeforeQueueing 與 enqueueInboundEventLocked
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
...
if (keyEventObj) { //通過jni方式回調(diào)java層
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
...
}
}
這部分其實(shí)就是PhoneWindowManager先做一次事件攔截處理操作,也就解釋了為什么有些點(diǎn)擊事件是不會(huì)傳給應(yīng)用的,而是在PhoneWindowManager那里就已經(jīng)被攔截了。具體邏輯不鋪開分析。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
...
break;
}
...
}
return needWake;
}
這里將keyArgs轉(zhuǎn)換成KeyEntery這種數(shù)據(jù)封裝,并添加到InputDispatcher的mInboundQueue里,最后喚醒InputDispacher線程。
最后簡單總結(jié)一下整個(gè)InputReader獲取事件流程:
在InputManager執(zhí)行start的時(shí)候InputReaderThread->run(),接著會(huì)執(zhí)行 mReader->loopOnce();
內(nèi)部邏輯主要分三塊:
獲取事件:
getEvents時(shí),打開"/dev/input/"目錄下的input設(shè)備,并將其注冊到epoll的監(jiān)控隊(duì)列中。這樣一旦對應(yīng)設(shè)備上有可讀的input事件,則epool_wait()就會(huì)返回,并帶回deviceid,找到具體的device。整個(gè)事件的獲取中,除了input事件,設(shè)備的打開關(guān)閉等信息,也要包裝成event,上報(bào)給InputReader。
處理事件:
processEventsForDeviceLocked 調(diào)用對應(yīng)的InputDevice處理Input事件,而InputDevice又會(huì)去匹配上對應(yīng)的InputMapper來處理對應(yīng)事件。(在InputDevice中,存儲著許多InputMapper,每種InputMapper對應(yīng)一類Device,例如:Touch、Keyboard、Vibrator等等……)而調(diào)用InputDevice的process函數(shù),就是將Input事件傳遞給每一個(gè)InputMapper,匹配的InputMapper就會(huì)對Input事件進(jìn)行處理,不匹配的則會(huì)忽略。而對應(yīng)的InputMapper最終會(huì)按對應(yīng)的NotifyArgs數(shù)據(jù)結(jié)構(gòu)對事件進(jìn)行封裝,并加入到ArgsQueue中。
傳遞事件:
flush會(huì)將ArgsQueue中的每一個(gè)Arg取出來交由innerListener對應(yīng)的InputDispacher執(zhí)行對應(yīng)類型的notify方法,將keyArgs轉(zhuǎn)換成KeyEntery這種數(shù)據(jù)封裝,并添加到InputDispatcher的mInboundQueue里,最后喚醒InputDispacher線程。
最后放上整體流程圖以及時(shí)序圖


到這里,整個(gè)的input事件的獲取就已經(jīng)完成了。