1. 回顧

我們知道Android輸入系統(tǒng)是Reader線程通過驅(qū)動(dòng)程序得到上報(bào)的輸入事件,還要經(jīng)過處理,才可以將輸入事件發(fā)送給應(yīng)用程序,現(xiàn)在回顧一下是具體做哪些處理。

  1. 首先Reader線程會(huì)將輸入事件放入mInboundQueue隊(duì)列當(dāng)中,但是放入隊(duì)列之前需要進(jìn)行稍加處理。
    1.1 處理類型
    - 緊急事件,馬上處理(來電振鈴時(shí),按下音量鍵,會(huì)馬上靜音)
    - 對(duì)輸入事件添加Flag,決定輸入事件是否傳給用戶

  2. Dispatch線程從mInboundQueue中取出事件,稍加處理之后,查找到目標(biāo)的應(yīng)用程序后,便會(huì)放入某個(gè)應(yīng)用程序的輸出隊(duì)列(mOutBoundQueue)

  3. 從輸出隊(duì)列中將事件取出,發(fā)送給應(yīng)用程序

2. Dispatch前處理總體分析

2.1 命令隊(duì)列為空時(shí)時(shí)候
  • 從mIboundQueue取出事件

  • 用它來生成一個(gè)命令,放入命令隊(duì)列或者直接丟棄(對(duì)于!Pass_To_User的事件)

  • 對(duì)于經(jīng)過處理的事件,dispatch它

    • 對(duì)于Global Key丟棄

    • System Key 丟棄

    • User Key 找到target,dispatch

InputDispatch.cpp
if (!haveCommandsLocked()) {
    dispatchOnceInnerLocked(&nextWakeupTime);
}
2.2 命令隊(duì)列有數(shù)據(jù),執(zhí)行命令
  • Global Key 發(fā)廣播

  • System Key 直接處理

  • User Key 不做處理

InputDispatch.cpp
if (runCommandsLockedInterruptible()) {
    nextWakeupTime = LONG_LONG_MIN;
}

3. dispatch前處理情景分析

3.1 !Pass_To_User
  • 當(dāng)policyFlags = !Pass_To_User,則會(huì)執(zhí)行dispatchOnceInnerLocked函數(shù),設(shè)置dropreason

DropReason dropReason = DROP_REASON_NOT_DROPPED;if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        dropReason = DROP_REASON_POLICY;
} else if (!mDispatchEnabled) {
        dropReason = DROP_REASON_DISABLED;
}
  • 假設(shè)是一個(gè)按鍵類型的輸入事件,便會(huì)調(diào)用dispatchKeyLocked處理

// Clean up if dropping the event.if (*dropReason != DROP_REASON_NOT_DROPPED) {
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
            ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);        return true;
}
3.2 Pass_To_User
  • 需要分為Global Key/System Key/User Key三種情況,但是都是首先放入命令隊(duì)列中,并執(zhí)行命令,執(zhí)行的命令根據(jù)各個(gè)按鍵的返回值決定。

  • 放入命令隊(duì)列

if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
        CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);        if (mFocusedWindowHandle != NULL) {
            commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;return false; // wait for the command to run
  • 執(zhí)行命令

if (runCommandsLockedInterruptible()) {
    nextWakeupTime = LONG_LONG_MIN;
}
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();

Command command = commandEntry->command;
(this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'//command執(zhí)行doInterceptKeyBeforeDispatchingLockedInterruptible函數(shù)
//最終調(diào)用PhoneWindowManager.java里面的同名函數(shù)nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);

mLock.lock();if (delay < 0) {
    entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; //忽略按鍵不會(huì)再次上傳給用戶} else if (!delay) {
    entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
    entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
    entry->interceptKeyWakeupTime = now() + delay;
}
  • 處理全局按鍵(Global Key)的代碼,返回-1,根據(jù)Global_Key.xml發(fā)送廣播給某個(gè)主鍵

    if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {return -1;
    }
  • System Key:直接處理,return -1,意味著不會(huì)上傳給APP

  • User Key:return 0,事件解析結(jié)果是continue,讓APP來處理。再次執(zhí)行dispatchOnceInnerLocked,最終會(huì)找到目標(biāo)應(yīng)用程序,然后將該事件發(fā)給應(yīng)用程序

    // Identify targets.Vector<InputTarget> inputTargets;int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
    entry, inputTargets, nextWakeupTime);
    // Dispatch the key.dispatchEventLocked(currentTime, entry, inputTargets);

4. 總結(jié)

本篇博文主要分析dispatc前的處理過程,如下圖所示:

  1. 對(duì)于Reader線程讀到的輸入事件,會(huì)先進(jìn)行解析,解析之后進(jìn)行過濾,如果可以過濾就釋放,就不會(huì)放入mInBoundQueue隊(duì)列當(dāng)中,不可以過濾的話,無論是否Pass_To_User,都會(huì)放入mInBoundQueue隊(duì)列當(dāng)中

  2. 從mInBoundQueue隊(duì)列當(dāng)中取出輸入事件,判斷是否Pass_To_User,如果不是Pass_To_User則釋放掉,否則放入mCommandQueue當(dāng)中

  3. 再?gòu)膍CommandQueue隊(duì)列當(dāng)中,再次做解析,解析之后如果決定可以把他丟棄掉的話就直接release掉,否則則是放在mOutBoundQueue隊(duì)列中去,APP取出使用。下篇博文會(huì)具體分析這一步。
    seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

http://www.cnblogs.com/lkq1220/p/7170107.html