版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、Android ANR代碼分析(技術(shù)文檔)內(nèi)容目錄1 什么是ANR52 ANR代碼執(zhí)行流程52.1 事件分發(fā)超時ANR52.2 啟動輸入分發(fā)線程(InputDispatcherThread)52.3 輸入事件的分發(fā)流程72.4 ANR處理流程132.5 針對Service超時的ANR處理流程172.6 針對Broadcast超時的ANR處理流程182.7 ANR超時時間222.8 序列圖241 什么是ANRANR是“Application Not Responding”的縮寫,即“應(yīng)用程序無響應(yīng)”。在Android中,ActivityManagerService(簡稱AMS)和WindowMa
2、nagerService(簡稱WMS)會監(jiān)測應(yīng)用程序的響應(yīng)時間,如果應(yīng)用程序主線程(即UI線程)在超時時間內(nèi)對輸入事件沒有處理完畢,或者對特定操作沒有執(zhí)行完畢,就會出現(xiàn)ANR。對于輸入事件沒有處理完畢產(chǎn)生的ANR,Android會顯示一個對話框,提示用戶當(dāng)前應(yīng)用程序沒有響應(yīng),用戶可以選擇繼續(xù)等待或者關(guān)閉這個應(yīng)用程序(也就是殺掉這個應(yīng)用程序的進程)。2 ANR代碼執(zhí)行流程本文檔所有分析均基于Android 4.4原生代碼。2.1 事件分發(fā)超時ANR響應(yīng)事件超時的ANR流程大概如下,在系統(tǒng)輸入管理服務(wù)進程(InputManagerService)中有一個單獨線程(InputDispatcherTh
3、read)會專門管理輸入事件分發(fā),在該線程處理輸入事件的過程中,會調(diào)用InputDispatcher不斷的檢測處理過程是否超時,一旦超時,會通過一系列的回調(diào)通知WMS的notifyANR函數(shù),最終會觸發(fā)AMS中mHandler對象里的SHOW_NOT_RESPONDING_MSG這個事件并在AMS中進行相應(yīng)處理,此時界面上就會顯示系統(tǒng)ANR提示對話框。2.2 啟動輸入分發(fā)線程(InputDispatcherThread)InputDispatcherThread作為輸入事件分發(fā)處理的核心線程,會隨系統(tǒng)服務(wù)InputManagerService的啟動而啟動。.frameworkbaseservi
4、cesjavacomandroidserverinputInputManagerService.javapublic class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs public InputManagerService(Context context, Handler handler) . mPtr = nativeInit(this, mContext, mHandler.getLooper().g
5、etQueue(); public void start() Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); . InputManagerService在啟動時會調(diào)用nativeStart方法,其中會啟動InputDispatcherThread線程。具體代碼在JNI方法nativeInit和nativeStart中實現(xiàn)。.frameworkbaseservicesjnicom_android_server_input_InputManagerService.cppstatic jint nativeIni
6、t(JNIEnv* env, jclass clazz, jobject serviceObj, jobject contextObj, jobject messageQueueObj) . NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper(); im->incStrong(0); return reinterpret_cast<jint>(im);static void nativeStart(JNIEnv* env, jcla
7、ss clazz, jint ptr) NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); .在nativeInit中新建InputManager對象,并在nativeStart中調(diào)用InutManager的start方法。.frameworkbaseservicesinputInputManager.cppInputManager:InputManager( const sp<E
8、ventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize();vo
9、id InputManager:initialize() mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); status_t InputManager:start() status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); . return OK;在InputManager構(gòu)造方法中,會新建
10、InputDispatcher對象,該對象會做為一個核心對象來處理所有輸入事件分發(fā)邏輯。在initialize方法中,分發(fā)線程對象被建立,并在start方法中啟動InputDispatcherThread線程。2.3 輸入事件的分發(fā)流程輸入事件的分發(fā)邏輯主要是在InputDispatcher類中實現(xiàn)的。先看一下InputDispatcherThread線程類:.frameworkbaseservicesinputInputDispatcher.cppInputDispatcherThread:InputDispatcherThread(const sp<InputDispatcherIn
11、terface>& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) bool InputDispatcherThread:threadLoop() mDispatcher->dispatchOnce(); return true;該線程的loop方法中,只執(zhí)行InputDispatcher類的dispatchOnce方法。下面集中討論一下InputDispatcher類:void InputDispatcher:dispatchOnce() nsecs_t nextWakeupTime
12、= LONG_LONG_MAX; / acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); / Run a dispatch loop if there are no pending commands. / The dispatch loop might enqueue commands to run afterwards. if (!haveCommandsLocked() dispatchOnceInnerLocked(&nextWakeupTime); / Run all pendin
13、g commands if there are any. / If any commands were run then force the next poll to wake up immediately. if (runCommandsLockedInterruptible() nextWakeupTime = LONG_LONG_MIN; / release lock / Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int time
14、outMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis);InputDispatcher類維護了一個command隊列,在dispatchOnce方法中會檢查該隊列中是否有command項,沒有的話會調(diào)用dispatchOnceInnerLocked方法做進一步處理,有的話則依序處理隊列中所有command,并設(shè)置等待時間觸發(fā)下一次輪詢。DispatchOnceInnerLocked方法主要是檢查是否有pending event,有的話就進行分發(fā)
15、處理,下面具體關(guān)注與ANR相關(guān)的部分代碼。void InputDispatcher:dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) nsecs_t currentTime = now(); . switch (mPendingEvent->type) . case EventEntry:TYPE_KEY: KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); . done = dispatchKeyLocked(currentTime, typedEntry
16、, &dropReason, nextWakeupTime); break; case EventEntry:TYPE_MOTION: MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); . done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; default: ALOG_ASSERT(false); break; 根據(jù)輸入事件的類型進行分發(fā)處理,和ANR相關(guān)
17、的有兩種類型:按鍵和觸摸。先看按鍵事件處理:bool InputDispatcher:dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) . / Identify targets. Vector<InputTarget> inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets,
18、 nextWakeupTime); if (injectionResult = INPUT_EVENT_INJECTION_PENDING) return false; setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) return true; addMonitoringTargetsLocked(inputTargets); / Dispatch the key. dispatchEventLocked(currentTime, e
19、ntry, inputTargets); return true;.int32_t InputDispatcher:findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) int32_t injectionResult; / If there is no currently focused window and no focused application /
20、 then drop the event. if (mFocusedWindowHandle = NULL) if (mFocusedApplicationHandle != NULL) injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application t
21、hat may eventually add a window " "when it finishes starting up."); goto Unresponsive; ALOGI("Dropping event because there is no focused window or focused application."); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; . / If the currently focused window is paus
22、ed then keep waiting. if (mFocusedWindowHandle->getInfo()->paused) injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, "Waiting because the focused window is paused."); goto Unresponsive; / If the currentl
23、y focused window is still working on previous events then keep waiting. if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry) injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, "Waiting beca
24、use the focused window has not finished " "processing the input events that were previously delivered to it."); goto Unresponsive; .在該處理過程中,有一步是獲取響應(yīng)該事件的window target,主要是調(diào)用findFocusedWindowTargetsLocked完成。對此有三種情況,系統(tǒng)會認為沒有ready的target:1)沒有找到focused window和focused application; 2) focused
25、window當(dāng)前正處于pause狀態(tài); 3)focused window還沒有處理完之前的事件。這些時候,handleTargetsNotReadyLocked方法就會被調(diào)用來處理這些異常情況。/ Default input dispatching timeout if there is no focused application or paused window/ from which to determine an appropriate dispatching timeout.const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000
26、* 1000000LL; / 5 32_t InputDispatcher:handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) . if (applicationHan
27、dle = NULL && windowHandle = NULL) if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = f
28、alse; mInputTargetWaitApplicationHandle.clear(); else if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) nsecs_t timeout; if (windowHandle != NULL) timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); else if (applicationHandle != NULL) timeou
29、t = applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT); else timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout;
30、mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); . if (currentTime >= mInputTargetWaitTimeoutTime) onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, mInputTargetWaitStartTime, reason); / Force poll loop to wake up immediately on next
31、iteration once we get the / ANR response back from the policy. *nextWakeupTime = LONG_LONG_MIN; return INPUT_EVENT_INJECTION_PENDING; else / Force poll loop to wake up when timeout is due. if (mInputTargetWaitTimeoutTime < *nextWakeupTime) *nextWakeupTime = mInputTargetWaitTimeoutTime; return INP
32、UT_EVENT_INJECTION_PENDING; 當(dāng)?shù)却龝r間超時之后,就會觸發(fā)ANR事件,并調(diào)用onANRLocked方法來做進一步處理。再看觸摸事件的流程:bool InputDispatcher:dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) Vector<InputTarget> inputTargets; bool conflictingPointerActions = false; int32
33、_t injectionResult; if (isPointerEvent) / Pointer event. (eg. touchscreen) injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); else / Non touch event. (eg. trackball) injectionResult = findFocusedWindowTargetsLocked(curr
34、entTime, entry, inputTargets, nextWakeupTime); .int32_t InputDispatcher:findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) . / If there is an error window but it is no
35、t taking focus (typically because / it is invisible) then wait for it. Any other focused window may in / fact be in ANR state. if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) injectionResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, NULL, nex
36、tWakeupTime, "Waiting because a system error window is about to be displayed."); injectionPermission = INJECTION_PERMISSION_UNKNOWN; goto Unresponsive; . / Ensure all touched foreground windows are ready for new input. for (size_t i = 0; i < mTempTouchState.windows.size(); i+) const Tou
37、chedWindow& touchedWindow = mTempTouchState.windowsi; if (touchedWindow.targetFlags & InputTarget:FLAG_FOREGROUND) / If the touched window is paused then keep waiting. if (touchedWindow.windowHandle->getInfo()->paused) injectionResult = handleTargetsNotReadyLocked(currentTime, entry, N
38、ULL, touchedWindow.windowHandle, nextWakeupTime, "Waiting because the touched window is paused."); goto Unresponsive; / If the touched window is still working on previous events then keep waiting. if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry) injectio
39、nResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, touchedWindow.windowHandle, nextWakeupTime, "Waiting because the touched window has not finished " "processing the input events that were previously delivered to it."); goto Unresponsive; 該流程ANR相關(guān)部分與按鍵處理流程類似,對于異常情況最終
40、也調(diào)用handleTargetsNotReadyLocked方法來處理。2.4 ANR處理流程void InputDispatcher:onANRLocked( nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) . CommandEntry* comm
41、andEntry = postCommandLocked( & InputDispatcher:doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; commandEntry->inputWindowHandle = windowHandle; commandEntry->reason = reason;InputDispatcher類的onANRLocked方法,會在command隊列中post一個command,在處理該command時會
42、調(diào)用關(guān)聯(lián)的doNotifyANRLockedInterruptible方法。void InputDispatcher:doNotifyANRLockedInterruptible( CommandEntry* commandEntry) . nsecs_t newTimeout = mPolicy->notifyANR( commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle, commandEntry->reason); .該方法會調(diào)用policy接口的notifyANR方法,其中通過
43、com_android_server_input_InputManagerService.cpp中的JNI接口調(diào)用InputManagerService的notifyANR方法,該方法也是一個wrapper method,最終實現(xiàn)是在InputMonitor類的notifyANR方法中。.frameworkbaseservicesjavacomandroidserverinputInputManagerService.java private long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHan
44、dle inputWindowHandle, String reason) return mWindowManagerCallbacks.notifyANR( inputApplicationHandle, inputWindowHandle, reason); 通過一系列調(diào)用,最終由ActivityManagerService彈出ANR對話框向用戶提示“應(yīng)用無響應(yīng)”信息。.frameworkbaseservicesjavacomandroidserverwmInputMonitor.java public long notifyANR(InputApplicationHandle input
45、ApplicationHandle, InputWindowHandle inputWindowHandle, String reason) . if (appWindowToken != null && appWindowToken.appToken != null) try / Notify the activity manager about the timeout and let it decide whether / to abort dispatching or keep waiting. boolean abort = appWindowToken.appToke
46、n.keyDispatchingTimedOut(reason); if (! abort) / The activity manager declined to abort dispatching. / Wait a bit longer and timeout again later. return appWindowToken.inputDispatchingTimeoutNanos; catch (RemoteException ex) else if (windowState != null) try / Notify the activity manager about the t
47、imeout and let it decide whether / to abort dispatching or keep waiting. long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut( windowState.mSession.mPid, aboveSystem, reason); if (timeout >= 0) / The activity manager declined to abort dispatching. / Wait a bit longer and tim
48、eout again later. return timeout; catch (RemoteException ex) return 0; / abort dispatching .frameworkbaseservicesjavacomandroidserveramActivityManagerService.java public boolean inputDispatchingTimedOut(final ProcessRecord proc, final ActivityRecord activity, final ActivityRecord parent, final boolean aboveSystem, String reason) . mHandler.post(new Runnable() Override public void ru
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度企業(yè)債券發(fā)行合同4篇
- 2025年度個人房產(chǎn)買賣合同違約金計算范本4篇
- 教育變革下的自然課堂-以小學(xué)生為對象的探究教學(xué)法應(yīng)用
- 教育技術(shù)助力的小學(xué)生圖書引導(dǎo)策略匯報
- 個人養(yǎng)老保險購買合同2024年度3篇
- 二零二五版互聯(lián)網(wǎng)金融平臺用戶協(xié)議與風(fēng)險提示2篇
- 二零二五年度高端不銹鋼制品制造與安裝服務(wù)合同3篇
- 二零二五版國際旅游導(dǎo)游勞動合同模板4篇
- 二零二五年度職業(yè)教育院校教師招聘勞動合同樣本3篇
- 2025年度人工智能助手軟件開發(fā)及商業(yè)化推廣合同4篇
- 2024年公需科目培訓(xùn)考試題及答案
- 2024年江蘇鑫財國有資產(chǎn)運營有限公司招聘筆試沖刺題(帶答案解析)
- 2024年遼寧石化職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測試題庫含答案
- 廣西桂林市2023-2024學(xué)年高二上學(xué)期期末考試物理試卷
- 財務(wù)指標與財務(wù)管理
- 部編版二年級下冊道德與法治第三單元《綠色小衛(wèi)士》全部教案
- 【京東倉庫出庫作業(yè)優(yōu)化設(shè)計13000字(論文)】
- 保安春節(jié)安全生產(chǎn)培訓(xùn)
- 初一語文上冊基礎(chǔ)知識訓(xùn)練及答案(5篇)
- 血液透析水處理系統(tǒng)演示
- GB/T 27030-2006合格評定第三方符合性標志的通用要求
評論
0/150
提交評論