日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程

發(fā)布時(shí)間:2025/5/22 Android 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

關(guān)聯(lián)系列
解析WMS系列
深入理解JNI系列
輸入系統(tǒng)系列

前言

在上一篇文章中,我們學(xué)習(xí)了輸入事件的處理,輸入事件會(huì)交由InputDispatcher進(jìn)行分發(fā),那么InputDispatcher是如何進(jìn)行分發(fā)的?這篇文章會(huì)給你答案。

1.InputReader的加工類型

在Android輸入系統(tǒng)(二)IMS的啟動(dòng)過程和輸入事件的處理這篇文章中,我們知道InputReader會(huì)對原始輸入事件進(jìn)行加工,如果事件的類型為按鍵類型的事件,就會(huì)調(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有三個(gè)子類,分別是NotifyKeyArgs、NotifyMotionArgs和NotifySwichArgs,這說明InputReader對原始輸入事件加工后,最終會(huì)得出三種事件類型,分別是key事件、Motion事件和Swich事件,這些事件會(huì)交由InputDispatcher來進(jìn)行分發(fā),如下圖所示。

2.InputDispatcher的分發(fā)過程

不同的事件類型有著不同的分發(fā)過程,其中Swich事件的處理是沒有派發(fā)過程的,在InputDispatcher的notifySwitch函數(shù)中會(huì)將Swich事件交由InputDispatcherPolicy來處理。本系列文章一直講解key事件相關(guān),這次換一下,以Motion事件的分發(fā)過程來進(jìn)行舉例,對key事件分發(fā)事件有興趣的可以自行去看源碼,本質(zhì)上都差不多。

2.1 喚醒InputDispatcherThread

InputDispatcher的notifyMotion函數(shù)用來喚醒InputDispatcherThread。 frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ... #endif//檢查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,就會(huì)直接return,這次事件不再進(jìn)行分發(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)部會(huì)檢查觸控點(diǎn)的數(shù)量pointerCount是否在合理范圍內(nèi)(小于1或者大于16都是不合理的),以及觸控點(diǎn)的ID是否在合理范圍內(nèi)(小于0或者大于31都是不合理的)。 注釋2處如果Motion事件需要交由InputFilter過濾,就會(huì)初始化MotionEvent,其作用就是用NotifyMotionArgs中的事件參數(shù)信息構(gòu)造一個(gè)MotionEvent,接著MotionEven會(huì)交給注釋3處的方法進(jìn)行過濾,如果返回值為false,這次Motion事件就會(huì)被忽略掉。 注釋4處,用NotifyMotionArgs中的事件參數(shù)信息構(gòu)造一個(gè)MotionEntry對象。注釋5處將MotionEntry傳入到enqueueInboundEventLocked函數(shù)中,其內(nèi)部會(huì)將MotionEntry添加到InputDispatcher的mInboundQueue隊(duì)列的末尾,并返回一個(gè)值needWake,代表InputDispatcherThread是否需要喚醒,如果需要喚醒就調(diào)用注釋6處的代碼來喚醒InputDispatcherThread。

2.2 InputDispatcher進(jìn)行分發(fā)

InputDispatcherThread被喚醒后,會(huì)執(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的緩存隊(duì)列中是否有等待處理的命令,如果沒有就會(huì)執(zhí)行注釋2處的dispatchOnceInnerLocked函數(shù),用來將輸入事件分發(fā)給合適的。注釋3處獲取當(dāng)前的時(shí)間,結(jié)合注釋4處,得出InputDispatcherThread需要睡眠的時(shí)間為timeoutMillis。最后調(diào)用Looper的pollOnce函數(shù)使InputDispatcherThread進(jìn)入睡眠狀態(tài),并將它的最長的睡眠的時(shí)間設(shè)置為timeoutMillis。當(dāng)有輸入事件產(chǎn)生時(shí),InputReader就會(huì)將睡眠狀態(tài)的InputDispatcherThread 喚醒,InputDispatcher會(huì)重新開始分發(fā)輸入事件。查看注釋2處的dispatchOnceInnerLocked函數(shù)是如何進(jìn)行事件分發(fā)的。 frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {...// 如果InputDispatcher被凍結(jié),則不進(jìn)行派發(fā)操作if (mDispatchFrozen) { #if DEBUG_FOCUSALOGD("Dispatch frozen. Waiting some more."); #endifreturn;}//如果isAppSwitchDue為true,說明沒有及時(shí)響應(yīng)HOME鍵等操作bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;//1if (mAppSwitchDueTime < *nextWakeupTime) {//2*nextWakeupTime = mAppSwitchDueTime;}//如果還沒有待分發(fā)的事件,去mInboundQueue中取出一個(gè)事件if (! mPendingEvent) {//如果mInboundQueue為空,并且沒有待分發(fā)的事件,就returnif (mInboundQueue.isEmpty()) {...if (!mPendingEvent) {return;}} else {//如果mInboundQueue不為空,取隊(duì)列頭部的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);//如果沒有及時(shí)響應(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能夠快速處理下一個(gè)分發(fā)事件*nextWakeupTime = LONG_LONG_MIN;//7 } 復(fù)制代碼

InputDispatcher的dispatchOnceInnerLocked函數(shù)的代碼比較長,這里截取了和Motion事件的分發(fā)相關(guān)的主要源碼。主要做了以下幾件事。

  • InputDispatcher的凍結(jié)處理 如果當(dāng)前InputDispatcher被凍結(jié),則不進(jìn)行派發(fā)操作,InputDispatcher有三種狀態(tài),分別是正常狀態(tài)、凍結(jié)狀態(tài)和禁用狀態(tài),可以通過InputDispatcher的setInputDispatchMode函數(shù)來設(shè)置。
  • 窗口切換操作處理 注釋1處的mAppSwitchDueTime ,代表了App最近發(fā)生窗口切換操作時(shí)(比如按下Home鍵、掛斷電話),該操作事件最遲的分發(fā)時(shí)間。如果這個(gè)時(shí)候,mAppSwitchDueTime小于等于當(dāng)前系統(tǒng)時(shí)間,說明沒有及時(shí)響應(yīng)窗口切換操作,則isAppSwitchDue的值設(shè)置為true。 注釋2處,如果mAppSwitchDueTime小于nextWakeupTime(下一次InputDispatcherThread醒來的時(shí)間),就將mAppSwitchDueTime賦值給nextWakeupTime,這樣當(dāng)InputDispatcher處理完分發(fā)事件后,會(huì)第一時(shí)間處理窗口切換操作。
  • 取出事件 如果沒有待分發(fā)的事件,就從mInboundQueue中取出一個(gè)事件,如果mInboundQueue為空,并且沒有待分發(fā)的事件,就return,如果mInboundQueue不為空,取隊(duì)列頭部的EventEntry賦值給mPendingEvent,mPendingEvent的類型為EventEntry對象指針。
  • 事件丟棄 注釋3處的dropReason代表了事件丟棄的原因,它的默認(rèn)值為DROP_REASON_NOT_DROPPED,代表事件不被丟棄。 注釋4處根據(jù)mPendingEvent的type做區(qū)分處理,這里主要截取了對Motion類型的處理。經(jīng)過過濾,會(huì)調(diào)用注釋5處的dispatchMotionLocked函數(shù)為這個(gè)事件尋找合適的窗口。
  • 后續(xù)處理 如果注釋5處的事件分發(fā)成功,則會(huì)在注釋6處調(diào)用releasePendingEventLocked函數(shù),其內(nèi)部會(huì)將mPendingEvent的值設(shè)置為Null,并將mPendingEvent指向的對象內(nèi)存釋放掉。注釋7處將nextWakeupTime的值設(shè)置為LONG_LONG_MIN,這是為了讓InputDispatcher能夠快速處理下一個(gè)分發(fā)事件。
  • 后記

    本文講解了InputReader的加工類型和InputDispatcher的分發(fā)過程,由于文章篇幅的原因,InputDispatcher的分發(fā)過程還有一部分沒有講解,這一部分就是事件分發(fā)到目標(biāo)窗口的過程,會(huì)在本系列的下一篇文章進(jìn)行講解。


    分享大前端、Java、跨平臺(tái)等技術(shù),關(guān)注職業(yè)發(fā)展和行業(yè)動(dòng)態(tài)。

    總結(jié)

    以上是生活随笔為你收集整理的Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。