1 InputDispatcher代碼解析第一部分
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
//條件編譯指令
#if DEBUG_INBOUND_EVENT_DETAILS
if (args->action != AMOTION_EVENT_ACTION_MOVE) {
//當(dāng)前動作不是AMOTION_EVENT_ACTION_MOVE
ALOGD("Cnt:%d notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
"displayId=%" PRId32 ", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
"yCursorPosition=%f, downTime=%" PRId64,
(((args->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) ||
((args->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN))
? (mMotionCntByDisplay[args->displayId] == INT_MAX
? INT_MAX : (mMotionCntByDisplay[args->displayId]++))
: -1,
args->id, args->eventTime, args->deviceId, args->source, args->displayId,
args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
args->xCursorPosition, args->yCursorPosition, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
//遍歷多指,每個(gè)觸控點(diǎn)的數(shù)據(jù)
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
"touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
"orientation=%f",
i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
}
#endif
//驗(yàn)證是否是有效motion事件
if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
args->pointerProperties)) {
return;
}
uint32_t policyFlags = args->policyFlags;
//定義InputReader上來的事件是值得信任的
policyFlags |= POLICY_FLAG_TRUSTED;
android::base::Timer t;
//事件入隊(duì)前通過策略是java端(InputManagerService)進(jìn)行攔截
mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
//判斷事件是否需要過濾 可以通過setInputFilterEnabled設(shè)置
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
args->action, args->actionButton, args->flags, args->edgeFlags,
args->metaState, args->buttonState, args->classification, 1 /*xScale*/,
1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision,
args->yPrecision, args->xCursorPosition, args->yCursorPosition,
args->downTime, args->eventTime, args->pointerCount,
args->pointerProperties, args->pointerCoords);
//添加過濾flag
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
//policy消費(fèi)了當(dāng)次事件
return; // event was consumed by the filter
}
mLock.lock();
}
// Just enqueue a new motion event.
//構(gòu)建觸摸事件
MotionEntry* newEntry =
new MotionEntry(args->id, args->eventTime, args->deviceId, args->source,
args->displayId, policyFlags, args->action, args->actionButton,
args->flags, args->metaState, args->buttonState,
args->classification, args->edgeFlags, args->xPrecision,
args->yPrecision, args->xCursorPosition, args->yCursorPosition,
args->downTime, args->pointerCount, args->pointerProperties,
args->pointerCoords, 0, 0);
//進(jìn)入dispatcher的隊(duì)列等待dispatcher處理派發(fā)
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
//派發(fā)隊(duì)列來事件了,喚醒InputDispatcher
mLooper->wake();
}
}
1 根據(jù)inputReader上來的數(shù)據(jù)參數(shù)action判斷如果不是AMOTION_EVENT_ACTION_MOVE
打印inputReader上報(bào)上來的數(shù)據(jù)信息,如果涉及多指
會遍歷每一個(gè)觸控點(diǎn)數(shù)據(jù)打印。
2 驗(yàn)證是否是有效事件
3 設(shè)置事件是值得信任的
4 事件進(jìn)入隊(duì)列前通過dispatchPolicy進(jìn)行事件攔截
5 判斷事件是否需要過濾需要就添加POLICY_FLAG_FILTERED標(biāo)記,如果事件被過濾掉了就直接return了,如果事件沒被過濾掉。
6 根據(jù)inputreader上來的數(shù)據(jù)構(gòu)建觸摸事件
7 觸摸事件構(gòu)建成功 喚醒InputDispatcher線程處理事件
1.1 驗(yàn)證是否是有效事件
static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
const PointerProperties* pointerProperties) {
if (!isValidMotionAction(action, actionButton, pointerCount)) {
//驗(yàn)證action是否有效
ALOGE("Motion event has invalid action code 0x%x", action);
return false;
}
if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
//驗(yàn)證觸控點(diǎn)數(shù)量是否正常
ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.",
pointerCount, MAX_POINTERS);
return false;
}
BitSet32 pointerIdBits;
for (size_t i = 0; i < pointerCount; i++) {
int32_t id = pointerProperties[i].id;
if (id < 0 || id > MAX_POINTER_ID) {
//驗(yàn)證Pointer Id是否正常
ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id,
MAX_POINTER_ID);
return false;
}
if (pointerIdBits.hasBit(id)) {
//驗(yàn)證pointer的id 是否有對應(yīng)的bit
ALOGE("Motion event has duplicate pointer id %d", id);
return false;
}
pointerIdBits.markBit(id);
}
return true;
}
1 isValidMotionAction 驗(yàn)證事件的action類型是否有效
2 驗(yàn)證觸控點(diǎn)數(shù)量正常
3 驗(yàn)證觸控點(diǎn)id是否正常
1.2 dispatchPolicy進(jìn)行事件攔截
void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
bool interactive = mInteractive.load();
if (interactive) {
//flag定義當(dāng)一個(gè)輸入事件攜帶了 POLICY_FLAG_INTERACTIVE 標(biāo)志時(shí),
//系統(tǒng)可能會將其視為需要交互式處理的事件,這意味著該事件可能需要立即響應(yīng)
//事件是否需要立即響應(yīng)
policyFlags |= POLICY_FLAG_INTERACTIVE;
}
//攜帶了 POLICY_FLAG_INJECTED 標(biāo)志時(shí),
//系統(tǒng)會將其視為是由應(yīng)用程序或者其他實(shí)體主動注入(inject)到輸入事件流中的事件
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
if (policyFlags & POLICY_FLAG_INTERACTIVE) {
//當(dāng)輸入事件攜帶了這個(gè)標(biāo)志時(shí),系統(tǒng)會將其視為需要將事件傳遞給用戶進(jìn)行處理。
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
displayId, when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingNonInteractive")) {
wmActions = 0;
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
if (interactive) {
//如果是其他注入的事件(滿足可交互) 也可以發(fā)給用戶
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
}
策略過濾會回調(diào)到上層InputManagerService最后通過windowCallBack來考慮
1.3 InputFilter過濾
bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
ATRACE_CALL();
jobject inputEventObj;
JNIEnv* env = jniEnv();
//判斷事件類型
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
//轉(zhuǎn)換成key事件
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<const KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION:
//轉(zhuǎn)換成motion事件
inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
static_cast<const MotionEvent*>(inputEvent));
break;
default:
return true; // dispatch the event normally
}
if (!inputEventObj) {
ALOGE("Failed to obtain input event object for filterInputEvent.");
return true; // dispatch the event normally
}
// The callee is responsible for recycling the event.
//來到j(luò)ava層的InputManagerService
jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
inputEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
pass = true;
}
env->DeleteLocalRef(inputEventObj);
return pass;
}
native層根據(jù)事件類型將事件對象由c++轉(zhuǎn)換成java給到InputManagerService
final boolean filterInputEvent(InputEvent event, int policyFlags) {
synchronized (mInputFilterLock) {
if (mInputFilter != null) {
try {
mInputFilter.filterInputEvent(event, policyFlags);
} catch (RemoteException e) {
/* ignore */
}
return false;
}
}
event.recycle();
return true;
}
將事件給到InputFilter
final public void filterInputEvent(InputEvent event, int policyFlags) {
mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget();
}
通過Handler發(fā)送MSG_INPUT_EVENT消息
private final class H extends Handler {
public H(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INSTALL:
mHost = (IInputFilterHost) msg.obj;
if (mInboundInputEventConsistencyVerifier != null) {
mInboundInputEventConsistencyVerifier.reset();
}
if (mOutboundInputEventConsistencyVerifier != null) {
mOutboundInputEventConsistencyVerifier.reset();
}
onInstalled();
break;
case MSG_UNINSTALL:
try {
onUninstalled();
} finally {
mHost = null;
}
break;
case MSG_INPUT_EVENT: {
final InputEvent event = (InputEvent)msg.obj;
try {
if (mInboundInputEventConsistencyVerifier != null) {
mInboundInputEventConsistencyVerifier.onInputEvent(event, 0);
}
//處理輸入事件
onInputEvent(event, msg.arg1);
} finally {
event.recycle();
}
break;
}
}
}
最后由view的InputFilter處理事件
1.4 事件入派發(fā)隊(duì)列
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
//事件加入之前如果之前隊(duì)列是空的 要喚醒InputDispatcher
bool needWake = mInboundQueue.empty();
//添加隊(duì)列末尾
mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::Type::KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD("App switch is pending!");
#endif
mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::Type::MOTION: {
//檢查和修剪輸入事件隊(duì)列中的 Motion 事件
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
//mNextUnblockedEvent 保證下次事件可以及時(shí)響應(yīng)
mNextUnblockedEvent = entry;
needWake = true;
}
break;
}
case EventEntry::Type::FOCUS: {
LOG_ALWAYS_FATAL("Focus events should be inserted using enqueueFocusEventLocked");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
// nothing to do
break;
}
}
return needWake;
}
如果添加事件到派發(fā)隊(duì)列時(shí) 當(dāng)前隊(duì)列如果沒有事件那么needWake = true
2 InputDispatcher第二部分
void InputDispatcher::dispatchOnce() {
//下次喚醒時(shí)間 默認(rèn)無限長
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.
if (!haveCommandsLocked()) {
//保證命令隊(duì)列(一次事件處理完整結(jié)束)無事件才會執(zhí)行
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
//根據(jù)遍歷CommandQueue里的元素執(zhí)行command函數(shù)決定是否立刻喚醒
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
// If we are still waiting for ack on some events,
// we might have to wake up earlier to check if an app is anr'ing.
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
} // 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);
}
1 當(dāng)前commandQueue無command 或者一次事件完整處理完
執(zhí)行下一次事件處理
2 考慮遍歷commandQueue的元素來決定是否立刻喚醒派發(fā)線程
2.1 一次事件處理
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
//記錄當(dāng)前時(shí)間
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
//查看是否開啟派發(fā)處理
if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
//如果派發(fā)凍結(jié)退出當(dāng)次派發(fā) 等待下次派發(fā)
if (mDispatchFrozen) {
if (DEBUG_FOCUS) {
ALOGD("Dispatch frozen. Waiting some more.");
}
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
//如果應(yīng)用切換時(shí)間<當(dāng)前時(shí)間
//下次喚醒時(shí)間等于應(yīng)用切換時(shí)間
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
//如果mPendingEvent是null
if (mInboundQueue.empty()) {
//派發(fā)隊(duì)列也是空
if (isAppSwitchDue) {
//存在app切換操作
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
//清除AppSwitch事件應(yīng)用切換標(biāo)志為false
//為什么事件隊(duì)列為空 就不需要在等了呢
//原因 isAppSwitchDue 為 true
//代表下次事件一定是app切換事件 但是事件隊(duì)列沒有
//那么他肯定就不會再來了
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
//如果經(jīng)歷了應(yīng)用切換和重復(fù)按鍵情況都沒有事件那就可以退出
//等待下次隊(duì)列存在事件
return;
}
} else {
// Inbound queue has at least one entry.
//事件隊(duì)列不為空從事件隊(duì)列取出緩存事件
mPendingEvent = mInboundQueue.front();
//事件隊(duì)列移除取出的事件
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
//檢查緩存事件的flag是否有POLICY_FLAG_PASS_TO_USER flag
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(*mPendingEvent);
}
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
//定義丟棄原因
DropReason dropReason = DropReason::NOT_DROPPED;
//POLICY_FLAG_PASS_TO_USER
//標(biāo)記表示輸入法在處理用戶輸入時(shí),會充分尊重用戶的交互需求,
//讓用戶能夠參與到輸入過程并及時(shí)調(diào)整
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
//policyFlags沒有 POLICY_FLAG_PASS_TO_USER
//丟棄策略問題
dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
//如果未開啟派發(fā) 丟棄原因未啟用
dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
case EventEntry::Type::CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::Type::DEVICE_RESET: {
DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::Type::FOCUS: {
FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
dispatchFocusLocked(currentTime, typedEntry);
done = true;
dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
break;
}
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(*typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
//因?yàn)閼?yīng)用切換丟棄當(dāng)前事件 并且聲明丟棄原因
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
//如果存在mNextUnblockedEvent事件 需要丟棄當(dāng)次事件
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
//處理motion事件
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
if (done) {
//如果事件被丟棄
if (dropReason != DropReason::NOT_DROPPED) {
//Log打印事件丟棄原因
dropInboundEventLocked(*mPendingEvent, dropReason);
}
//記錄上次丟棄原因
mLastDropReason = dropReason;
//清除當(dāng)次緩存事件 開啟下一次事件循環(huán)
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
1 查看派發(fā)是否開啟
2 查看派發(fā)是否被凍結(jié) 例如橫豎屏轉(zhuǎn)換
3 檢查當(dāng)前是否處于應(yīng)用切換按鍵操作
4 獲取緩存事件
4.1 事件隊(duì)列有事件
直接從隊(duì)列頭部取出事件
4.2 事件隊(duì)列無事件
1 如果當(dāng)前是應(yīng)用切換狀態(tài) 那么可以直接重置應(yīng)用切換相關(guān)緩存
2 如果存在重復(fù)事件 則根據(jù)上次事件生成當(dāng)次事件
緩存事件為空 直接返回 等待下一次事件處理
5 檢查緩存事件Flag
POLICY_FLAG_PASS_TO_USER
標(biāo)記表示輸入法在處理用戶輸入時(shí),會充分尊重用戶的交互需求,
讓用戶能夠參與到輸入過程并及時(shí)調(diào)整 及時(shí)交互反饋
6 根據(jù)事件類型 強(qiáng)制轉(zhuǎn)換相關(guān)事件
7 根據(jù)應(yīng)用是否切換isAppSwitchDue
是否為stale event
下一次事件是否提前執(zhí)行mNextUnblockedEvent
來定義當(dāng)次事件丟棄原因
8 執(zhí)行dispatchMotionLocked 處理當(dāng)次motion事件
9 處理完成 根據(jù)dropReason 打印相關(guān)丟棄事件原因log
對丟棄原因進(jìn)行記錄
釋放當(dāng)次緩存事件
設(shè)置下次喚醒時(shí)間為LONG_LONG_MIN
2.2 dispatchMotionLocked函數(shù)處理
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
ATRACE_CALL();
// Preprocessing.
//如果當(dāng)前未處于派發(fā)中 那就設(shè)置當(dāng)次事件處于派發(fā)中
if (!entry->dispatchInProgress) {
entry->dispatchInProgress = true;
logOutboundMotionDetails("dispatchMotion - ", *entry);
}
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) {
//根據(jù)DropReason設(shè)置注入結(jié)果
setInjectionResult(entry,
*dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
: INPUT_EVENT_INJECTION_FAILED);
return true;
}
//確認(rèn)當(dāng)次事件是否為手指事件
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
//派發(fā)目標(biāo)集合
std::vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
//手指事件 根據(jù)touch找到合適窗口
injectionResult =
findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
//非手指觸摸事件 通過窗口焦點(diǎn)找到合適窗口
injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
}
//注入結(jié)果為INPUT_EVENT_INJECTION_PENDING
//退出當(dāng)次事件派發(fā) 等待下一次
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
//設(shè)置對應(yīng)事件的注入結(jié)果
setInjectionResult(entry, injectionResult);
if (injectionResult == INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
//如果注入結(jié)果為INPUT_EVENT_INJECTION_PERMISSION_DENIED
ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
}
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
//如果注入的結(jié)果不是成功 那么根據(jù)是否是手指觸摸事件生成cancel事件
//注入到事件隊(duì)列
CancelationOptions::Mode mode(isPointerEvent
? CancelationOptions::CANCEL_POINTER_EVENTS
: CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
// Add monitor channels from event's or focused display.
//查看當(dāng)前是否屬于touch的down事件
bool isShowTouchDump = false;
if ((entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN
|| (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) {
isShowTouchDump = true;
}
//根據(jù)touch事件或者key事件 打印相關(guān)log 窗口信息 等等
ALOGD("addGlobalMonitoringTargetsLocked isShowTouchDump: %s", isShowTouchDump ? "true" : "false");
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry), isShowTouchDump, false);
if (isPointerEvent) {
std::unordered_map<int32_t, TouchState>::iterator it =
mTouchStatesByDisplay.find(entry->displayId);
if (it != mTouchStatesByDisplay.end()) {
const TouchState& state = it->second;
if (!state.portalWindows.empty()) {
// The event has gone through these portal windows, so we add monitoring targets of
// the corresponding displays as well.
for (size_t i = 0; i < state.portalWindows.size(); i++) {
const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, false, false,
-windowInfo->frameLeft, -windowInfo->frameTop);
}
}
}
}
// Dispatch the motion.
//如果手指行為action存在沖突 那會生成cancel事件加入事件隊(duì)列在分發(fā)到窗口
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
//派發(fā)事件到指定窗口
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
1 查看當(dāng)前事件是否處于派發(fā)中
2 根據(jù)丟棄原因設(shè)置注入結(jié)果
3 判斷當(dāng)前事件是否為觸摸事件
4 查找touch窗口
5 根據(jù)查找窗口的結(jié)果進(jìn)行下一步動作
1 INPUT_EVENT_INJECTION_PENDING
當(dāng)前事件處于緩存狀態(tài)
退出當(dāng)前事件,等待下一次派發(fā)
2 INPUT_EVENT_INJECTION_PERMISSION_DENIED
當(dāng)前事件沒有權(quán)限
退出當(dāng)次事件
3 != INPUT_EVENT_INJECTION_SUCCEEDED
注入結(jié)果失敗
根據(jù)是否touch事件 生成對應(yīng)cancel 事件
加入事件隊(duì)列 等待下一次事件派發(fā)循環(huán)將事件給到對應(yīng)窗口
6 根據(jù)得到的輸入目標(biāo)窗口 遍歷打印相關(guān)log
7 如果touch事件存在沖突 和5.3一樣
8 將事件注入指定窗口
2.3 輸入事件進(jìn)入派發(fā)隊(duì)列
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(*eventEntry);
//遍歷touch的窗口
for (const InputTarget& inputTarget : inputTargets) {
//只要通道不為空
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
} else {
if (DEBUG_FOCUS) {
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
}
}
}
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"globalScaleFactor=%f, pointerIds=0x%x %s",
connection->getInputChannelName().c_str(), inputTarget.flags,
inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
inputTarget.getPointerInfoString().c_str());
#endif
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
return;
}
// Split a motion event if needed.
//需要拆分的事件
if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
"Entry type %s should not have FLAG_SPLIT",
EventEntry::typeToString(eventEntry->type));
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
MotionEntry* splitMotionEntry =
splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
if (DEBUG_FOCUS) {
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", *splitMotionEntry);
}
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
//不需要拆分的事件
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
檢查輸入目標(biāo)的標(biāo)志中是否包含InputTarget::FLAG_SPLIT。如果是拆分事件,會對事件類型進(jìn)行檢查,然后對原始的運(yùn)動事件進(jìn)行拆分處理,生成新的拆分事件,并將其加入到事件派發(fā)隊(duì)列中。最后釋放拆分事件的資源。
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
bool wasEmpty = connection->outboundQueue.empty();
// 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.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
輸入事件進(jìn)入派發(fā)隊(duì)列
這里涉及請求模式
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT
,表示將事件派發(fā)到輸入窗口,并將其標(biāo)記為鼠標(biāo)懸停退出事件。這通常用于處理鼠標(biāo)懸停操作。當(dāng)鼠標(biāo)從一個(gè)窗口的可接收懸停事件的區(qū)域移出時(shí),會觸發(fā)該標(biāo)志位對應(yīng)的派發(fā)操作,通知窗口處理鼠標(biāo)懸停退出的邏輯。
InputTarget::FLAG_DISPATCH_AS_OUTSIDE
表示將事件派發(fā)到輸入窗口,并將其標(biāo)記為外部觸摸事件。這通常用于處理觸摸事件在窗口之外的情況。當(dāng)觸摸事件發(fā)生在窗口之外時(shí),會觸發(fā)該標(biāo)志位對應(yīng)的派發(fā)操作,通知窗口處理外部觸摸事件的邏輯
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER
表示將事件派發(fā)到輸入窗口,并將其標(biāo)記為鼠標(biāo)懸停進(jìn)入事件。這通常用于處理鼠標(biāo)懸停操作。當(dāng)可接收懸停事件進(jìn)入一個(gè)窗口時(shí),會觸發(fā)該標(biāo)志位對應(yīng)的派發(fā)操作,通知窗口處理鼠標(biāo)懸停進(jìn)入的邏輯。
InputTarget::FLAG_DISPATCH_AS_IS
表示將事件派發(fā)到輸入窗口,并將其標(biāo)記為普通的輸入事件。這通常用于處理普通的輸入操作,如鍵盤輸入、鼠標(biāo)點(diǎn)擊等。當(dāng)普通的輸入事件發(fā)生時(shí),會觸發(fā)該標(biāo)志位對應(yīng)的派發(fā)操作,通知窗口處理普通的輸入事件的邏輯。
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT
表示將事件派發(fā)到輸入窗口,但是不會造成焦點(diǎn)的變化。這通常用于處理“滑動”場景,在滑動過程中,我們需要不斷向當(dāng)前焦點(diǎn)窗口發(fā)送滑動事件,但是不能改變窗口的焦點(diǎn)狀態(tài)
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER
表示將事件派發(fā)到輸入窗口,并且在派發(fā)事件時(shí)不會改變窗口的焦點(diǎn)狀態(tài)。這通常用于處理“滑動”場景,在滑動過程中,我們需要不斷向當(dāng)前焦點(diǎn)窗口發(fā)送滑動事件,但是不能改變窗口的焦點(diǎn)狀態(tài),直到滑動結(jié)束才能改變焦點(diǎn)狀態(tài)
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
switch (newEntry->type) {
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
// Assign a default value to dispatchEntry that will never be generated by InputReader,
// and assign a InputDispatcher value if it doesn't change in the if-else chain below.
constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
static_cast<int32_t>(IdGenerator::Source::OTHER);
dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
} else {
dispatchEntry->resolvedAction = motionEntry.action;
dispatchEntry->resolvedEventId = motionEntry.id;
}
}
// Enqueue the dispatch entry.
//通過調(diào)用dispatchEntry.release()方法,我們釋放了dispatchEntry智能指針的所有權(quán),
//并返回一個(gè)指向該對象的裸指針。然后,使用push_back()方法將該裸指針
//添加到connection對象的outboundQueue隊(duì)列的末尾。
//這樣做的目的是將dispatchEntry對象添加到outboundQueue隊(duì)列中,
//以便后續(xù)進(jìn)行處理或發(fā)送給其他組件。注意,由于我們已經(jīng)釋放了dispatchEntry的所有權(quán),
//所以在outboundQueue中存儲的是裸指針,而不是智能指針。
//需要確保在適當(dāng)?shù)臅r(shí)候管理和釋放這些指針,以避免內(nèi)存泄漏。
connection->outboundQueue.push_back(dispatchEntry.release());
}
1 根據(jù)InputTarget eventEntry InputTargetFlags 構(gòu)建dispatchEntry對象
2 根據(jù)EventEntry的類型是MOTION 構(gòu)建motionEntry
來設(shè)置dispatchEntry->resolvedAction dispatchEntry->resolvedEventId
3 dispatchEntry對象添加到outboundQueue隊(duì)列中
2.4 從派發(fā)隊(duì)列派發(fā)事件
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
//調(diào)整為窗口可用的指針數(shù)組
PointerCoords scaledCoords[MAX_POINTERS];
//當(dāng)前屏幕使用的坐標(biāo)數(shù)組
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// Set the X and Y offset and X and Y scale depending on the input source.
float xOffset = 0.0f, yOffset = 0.0f;
float xScale = 1.0f, yScale = 1.0f;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
float globalScaleFactor = dispatchEntry->globalScaleFactor;
xScale = dispatchEntry->windowXScale;
yScale = dispatchEntry->windowYScale;
xOffset = dispatchEntry->xOffset * xScale;
yOffset = dispatchEntry->yOffset * yScale;
//代表設(shè)備無關(guān)的坐標(biāo)轉(zhuǎn)換設(shè)備相關(guān)的坐標(biāo)
if (globalScaleFactor != 1.0f) {
//遍歷指針數(shù)量
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
//將當(dāng)前motionEntry->pointerCoords[i]賦值到scaledCoords[i]
scaledCoords[i] = motionEntry->pointerCoords[i];
// Don't apply window scale here since we don't want scale to affect raw
// coordinates. The scale will be sent back to the client and applied
// later when requesting relative coordinates.
//坐標(biāo)縮放調(diào)整
scaledCoords[i].scale(globalScaleFactor, 1 /* windowXScale */,
1 /* windowYScale */);
}
//將scaledCoords給到usingCoords
usingCoords = scaledCoords;
}
} else {
// We don't want the dispatch target to know.
//輸入目標(biāo)需要將坐標(biāo)歸零,清空scaledCoords數(shù)組
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i].clear();
}
//賦值給usingCoords
usingCoords = scaledCoords;
}
}
std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
// Publish the motion event.
//上傳該motion事件
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
motionEntry->deviceId, motionEntry->source,
motionEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
motionEntry->actionButton,
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
motionEntry->classification, xScale, yScale,
xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);
reportTouchEventForStatistics(*motionEntry);
break;
}
}
// Re-enqueue the event on the wait queue.
//從派發(fā)隊(duì)列中移除該事件
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
traceOutboundQueueLength(connection);
//在等待隊(duì)列中添加該事件
connection->waitQueue.push_back(dispatchEntry);
if (connection->responsive) {
//如果窗口無響應(yīng)將派發(fā)事件的超時(shí)時(shí)間和派發(fā)窗口token加入到ANR觸發(fā)器
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(connection);
}
}
}
1 確認(rèn)連接通道正常 且派發(fā)隊(duì)列事件不為空
2 outboundQueue頭部取出數(shù)據(jù)
設(shè)置分發(fā)時(shí)間 當(dāng)前時(shí)間
獲取超時(shí)時(shí)間間隔
設(shè)置超時(shí)時(shí)間
3 根據(jù)事件類型MOTION
創(chuàng)建窗口可用指針數(shù)組scaledCoords
usingCoords指向motion事件的pointerCoords
4 設(shè)置默認(rèn)x y 偏移 和 x y 縮放
5 判斷當(dāng)前source是POINTER 并且targetFlaget 不是InputTarget::FLAG_ZERO_COORDS標(biāo)志
6 全局縮放因子globalScaleFactor == 1.0f代表不需要調(diào)整設(shè)備坐標(biāo)
7 全局縮放因子globalScaleFactor != 1.0f 需要將當(dāng)前motionEntry->pointerCoords[i]通過縮放調(diào)整為scaledCoords[i]
同時(shí) usingCoords也被賦值為scaledCoords
8 如果targetFlaget 是InputTarget::FLAG_ZERO_COORDS標(biāo)志
需要將 scaledCoords數(shù)組信息清空 賦值給usingCoords
9 通過connection->inputPublisher 將motionEvent發(fā)布出去
10 connection->outboundQueue 派發(fā)隊(duì)列刪除該事件
11connection->waitQueue 等待隊(duì)列加入該事件
12 如果窗口無響應(yīng)將派發(fā)事件的超時(shí)時(shí)間和派發(fā)窗口token加入到ANR觸發(fā)器