Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程
關(guān)聯(lián)系列
解析WMS系列
深入理解JNI系列
輸入系統(tǒng)系列
前言
在上一篇文章中,我們學習了輸入事件的處理,輸入事件會交由InputDispatcher進行分發(fā),那么InputDispatcher是如何進行分發(fā)的?這篇文章會給你答案。
1.InputReader的加工類型
在Android輸入系統(tǒng)(二)IMS的啟動過程和輸入事件的處理這篇文章中,我們知道InputReader會對原始輸入事件進行加工,如果事件的類型為按鍵類型的事件,就會調(diào)用如下一段代碼。 frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...bool needWake;{ ...} // release lockif (needWake) {mLooper->wake();} } 復(fù)制代碼InputDispatcher的notifyKey方法用于喚醒InputDispatcherThread,它的參數(shù)NotifyKeyArgs是InputReader對按鍵類型的事件加工后得到的。 frameworks/native/services/inputflinger/InputListener.h
struct NotifyKeyArgs : public NotifyArgs {nsecs_t eventTime;int32_t deviceId;uint32_t source;uint32_t policyFlags;int32_t action;int32_t flags;int32_t keyCode;int32_t scanCode;int32_t metaState;nsecs_t downTime;inline NotifyKeyArgs() { }NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,int32_t metaState, nsecs_t downTime);NotifyKeyArgs(const NotifyKeyArgs& other);virtual ~NotifyKeyArgs() { }virtual void notify(const sp<InputListenerInterface>& listener) const; }; 復(fù)制代碼可以看到,NotifyKeyArgs結(jié)構(gòu)體繼承自NotifyArgs結(jié)構(gòu)體,如下圖所示。
NotifyArgs有三個子類,分別是NotifyKeyArgs、NotifyMotionArgs和NotifySwichArgs,這說明InputReader對原始輸入事件加工后,最終會得出三種事件類型,分別是key事件、Motion事件和Swich事件,這些事件會交由InputDispatcher來進行分發(fā),如下圖所示。2.InputDispatcher的分發(fā)過程
不同的事件類型有著不同的分發(fā)過程,其中Swich事件的處理是沒有派發(fā)過程的,在InputDispatcher的notifySwitch函數(shù)中會將Swich事件交由InputDispatcherPolicy來處理。本系列文章一直講解key事件相關(guān),這次換一下,以Motion事件的分發(fā)過程來進行舉例,對key事件分發(fā)事件有興趣的可以自行去看源碼,本質(zhì)上都差不多。
2.1 喚醒InputDispatcherThread
InputDispatcher的notifyMotion函數(shù)用來喚醒InputDispatcherThread。 frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ... //檢查Motion事件的參數(shù)是否有效if (!validateMotionEvent(args->action, args->actionButton,args->pointerCount, args->pointerProperties)) {//1return;}uint32_t policyFlags = args->policyFlags;policyFlags |= POLICY_FLAG_TRUSTED;mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);bool needWake;{ // acquire lockmLock.lock();//Motion事件是否需要交由InputFilter過濾if (shouldSendMotionToInputFilterLocked(args)) {//2mLock.unlock();MotionEvent event;//初始化MotionEvent,將NotifyMotionArgs中的參數(shù)信息賦值給MotionEvent中的參數(shù)event.initialize(args->deviceId, args->source, args->action, args->actionButton,args->flags, args->edgeFlags, args->metaState, args->buttonState,0, 0, args->xPrecision, args->yPrecision,args->downTime, args->eventTime,args->pointerCount, args->pointerProperties, args->pointerCoords);//表示已經(jīng)過濾了policyFlags |= POLICY_FLAG_FILTERED;//開始過濾,如果返回值為false,就會直接return,這次事件不再進行分發(fā)if (!mPolicy->filterInputEvent(&event, policyFlags)) {//3return; // event was consumed by the filter}mLock.lock();}/*** 4 */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);//5mLock.unlock();} // release lockif (needWake) {mLooper->wake();//6} } 復(fù)制代碼注釋1處用于檢查Motion事件的參數(shù)是否有效,其內(nèi)部會檢查觸控點的數(shù)量pointerCount是否在合理范圍內(nèi)(小于1或者大于16都是不合理的),以及觸控點的ID是否在合理范圍內(nèi)(小于0或者大于31都是不合理的)。 注釋2處如果Motion事件需要交由InputFilter過濾,就會初始化MotionEvent,其作用就是用NotifyMotionArgs中的事件參數(shù)信息構(gòu)造一個MotionEvent,接著MotionEven會交給注釋3處的方法進行過濾,如果返回值為false,這次Motion事件就會被忽略掉。 注釋4處,用NotifyMotionArgs中的事件參數(shù)信息構(gòu)造一個MotionEntry對象。注釋5處將MotionEntry傳入到enqueueInboundEventLocked函數(shù)中,其內(nèi)部會將MotionEntry添加到InputDispatcher的mInboundQueue隊列的末尾,并返回一個值needWake,代表InputDispatcherThread是否需要喚醒,如果需要喚醒就調(diào)用注釋6處的代碼來喚醒InputDispatcherThread。
2.2 InputDispatcher進行分發(fā)
InputDispatcherThread被喚醒后,會執(zhí)行InputDispatcherThread的threadLoop函數(shù): frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {mDispatcher->dispatchOnce();return true; } 復(fù)制代碼threadLoop函數(shù)中只調(diào)用了InputDispatcher的dispatchOnce函數(shù): frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;{ // acquire lockAutoMutex _l(mLock);mDispatcherIsAliveCondition.broadcast();if (!haveCommandsLocked()) {//1dispatchOnceInnerLocked(&nextWakeupTime);//2}if (runCommandsLockedInterruptible()) {nextWakeupTime = LONG_LONG_MIN;}} // release locknsecs_t currentTime = now();//3int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);//4mLooper->pollOnce(timeoutMillis); } 復(fù)制代碼注釋1處用于檢查InputDispatcher的緩存隊列中是否有等待處理的命令,如果沒有就會執(zhí)行注釋2處的dispatchOnceInnerLocked函數(shù),用來將輸入事件分發(fā)給合適的。注釋3處獲取當前的時間,結(jié)合注釋4處,得出InputDispatcherThread需要睡眠的時間為timeoutMillis。最后調(diào)用Looper的pollOnce函數(shù)使InputDispatcherThread進入睡眠狀態(tài),并將它的最長的睡眠的時間設(shè)置為timeoutMillis。當有輸入事件產(chǎn)生時,InputReader就會將睡眠狀態(tài)的InputDispatcherThread 喚醒,InputDispatcher會重新開始分發(fā)輸入事件。查看注釋2處的dispatchOnceInnerLocked函數(shù)是如何進行事件分發(fā)的。 frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {...// 如果InputDispatcher被凍結(jié),則不進行派發(fā)操作if (mDispatchFrozen) { ALOGD("Dispatch frozen. Waiting some more."); return;}//如果isAppSwitchDue為true,說明沒有及時響應(yīng)HOME鍵等操作bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;//1if (mAppSwitchDueTime < *nextWakeupTime) {//2*nextWakeupTime = mAppSwitchDueTime;}//如果還沒有待分發(fā)的事件,去mInboundQueue中取出一個事件if (! mPendingEvent) {//如果mInboundQueue為空,并且沒有待分發(fā)的事件,就returnif (mInboundQueue.isEmpty()) {...if (!mPendingEvent) {return;}} else {//如果mInboundQueue不為空,取隊列頭部的EventEntry賦值給mPendingEvent mPendingEvent = mInboundQueue.dequeueAtHead();traceInboundQueueLengthLocked();}if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {pokeUserActivityLocked(mPendingEvent);}resetANRTimeoutsLocked();}ALOG_ASSERT(mPendingEvent != NULL);bool done = false;DropReason dropReason = DROP_REASON_NOT_DROPPED;//3...switch (mPendingEvent->type) {//4...case EventEntry::TYPE_MOTION: {MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);//如果沒有及時響應(yīng)窗口切換操作if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {dropReason = DROP_REASON_APP_SWITCH;}//事件過期if (dropReason == DROP_REASON_NOT_DROPPED&& isStaleEventLocked(currentTime, typedEntry)) {dropReason = DROP_REASON_STALE;}//阻礙其他窗口獲取事件if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {dropReason = DROP_REASON_BLOCKED;}done = dispatchMotionLocked(currentTime, typedEntry,&dropReason, nextWakeupTime);//5break;}default:ALOG_ASSERT(false);break;}if (done) {if (dropReason != DROP_REASON_NOT_DROPPED) {dropInboundEventLocked(mPendingEvent, dropReason);}mLastDropReason = dropReason;//釋放本次事件處理的對象releasePendingEventLocked();//6//使得InputDispatcher能夠快速處理下一個分發(fā)事件*nextWakeupTime = LONG_LONG_MIN;//7 } 復(fù)制代碼InputDispatcher的dispatchOnceInnerLocked函數(shù)的代碼比較長,這里截取了和Motion事件的分發(fā)相關(guān)的主要源碼。主要做了以下幾件事。
后記
本文講解了InputReader的加工類型和InputDispatcher的分發(fā)過程,由于文章篇幅的原因,InputDispatcher的分發(fā)過程還有一部分沒有講解,這一部分就是事件分發(fā)到目標窗口的過程,會在本系列的下一篇文章進行講解。
分享大前端、Java、跨平臺等技術(shù),關(guān)注職業(yè)發(fā)展和行業(yè)動態(tài)。
總結(jié)
以上是生活随笔為你收集整理的Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 达拉草201771010105《面向对象
- 下一篇: vue 表单验证按钮事件交由父组件触发