![ANR代碼流程分析_第1頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/87c68980-5787-4b05-a4f2-d826f96135b7/87c68980-5787-4b05-a4f2-d826f96135b71.gif)
![ANR代碼流程分析_第2頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/87c68980-5787-4b05-a4f2-d826f96135b7/87c68980-5787-4b05-a4f2-d826f96135b72.gif)
![ANR代碼流程分析_第3頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/87c68980-5787-4b05-a4f2-d826f96135b7/87c68980-5787-4b05-a4f2-d826f96135b73.gif)
![ANR代碼流程分析_第4頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/87c68980-5787-4b05-a4f2-d826f96135b7/87c68980-5787-4b05-a4f2-d826f96135b74.gif)
![ANR代碼流程分析_第5頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/87c68980-5787-4b05-a4f2-d826f96135b7/87c68980-5787-4b05-a4f2-d826f96135b75.gif)
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Android ANR代碼分析(技術(shù)文檔)內(nèi)容目錄1 什么是ANR52 ANR代碼執(zhí)行流程52.1 事件分發(fā)超時(shí)ANR52.2 啟動(dòng)輸入分發(fā)線程(InputDispatcherThread)52.3 輸入事件的分發(fā)流程72.4 ANR處理流程132.5 針對(duì)Service超時(shí)的ANR處理流程172.6 針對(duì)Broadcast超時(shí)的ANR處理流程182.7 ANR超時(shí)時(shí)間222.8 序列圖241 什么是ANRANR是“Application Not Responding”的縮寫(xiě),即“應(yīng)用程序無(wú)響應(yīng)”。在Android中,ActivityManagerService(簡(jiǎn)稱AMS)和WindowMa
2、nagerService(簡(jiǎn)稱WMS)會(huì)監(jiān)測(cè)應(yīng)用程序的響應(yīng)時(shí)間,如果應(yīng)用程序主線程(即UI線程)在超時(shí)時(shí)間內(nèi)對(duì)輸入事件沒(méi)有處理完畢,或者對(duì)特定操作沒(méi)有執(zhí)行完畢,就會(huì)出現(xiàn)ANR。對(duì)于輸入事件沒(méi)有處理完畢產(chǎn)生的ANR,Android會(huì)顯示一個(gè)對(duì)話框,提示用戶當(dāng)前應(yīng)用程序沒(méi)有響應(yīng),用戶可以選擇繼續(xù)等待或者關(guān)閉這個(gè)應(yīng)用程序(也就是殺掉這個(gè)應(yīng)用程序的進(jìn)程)。2 ANR代碼執(zhí)行流程本文檔所有分析均基于Android 4.4原生代碼。2.1 事件分發(fā)超時(shí)ANR響應(yīng)事件超時(shí)的ANR流程大概如下,在系統(tǒng)輸入管理服務(wù)進(jìn)程(InputManagerService)中有一個(gè)單獨(dú)線程(InputDispatcherTh
3、read)會(huì)專門(mén)管理輸入事件分發(fā),在該線程處理輸入事件的過(guò)程中,會(huì)調(diào)用InputDispatcher不斷的檢測(cè)處理過(guò)程是否超時(shí),一旦超時(shí),會(huì)通過(guò)一系列的回調(diào)通知WMS的notifyANR函數(shù),最終會(huì)觸發(fā)AMS中mHandler對(duì)象里的SHOW_NOT_RESPONDING_MSG這個(gè)事件并在AMS中進(jìn)行相應(yīng)處理,此時(shí)界面上就會(huì)顯示系統(tǒng)ANR提示對(duì)話框。2.2 啟動(dòng)輸入分發(fā)線程(InputDispatcherThread)InputDispatcherThread作為輸入事件分發(fā)處理的核心線程,會(huì)隨系統(tǒng)服務(wù)InputManagerService的啟動(dòng)而啟動(dòng)。.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在啟動(dòng)時(shí)會(huì)調(diào)用nativeStart方法,其中會(huì)啟動(dòng)InputDispatcherThread線程。具體代碼在JNI方法nativeInit和nativeStart中實(shí)現(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對(duì)象,并在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)造方法中,會(huì)新建
10、InputDispatcher對(duì)象,該對(duì)象會(huì)做為一個(gè)核心對(duì)象來(lái)處理所有輸入事件分發(fā)邏輯。在initialize方法中,分發(fā)線程對(duì)象被建立,并在start方法中啟動(dòng)InputDispatcherThread線程。2.3 輸入事件的分發(fā)流程輸入事件的分發(fā)邏輯主要是在InputDispatcher類中實(shí)現(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類維護(hù)了一個(gè)command隊(duì)列,在dispatchOnce方法中會(huì)檢查該隊(duì)列中是否有command項(xiàng),沒(méi)有的話會(huì)調(diào)用dispatchOnceInnerLocked方法做進(jìn)一步處理,有的話則依序處理隊(duì)列中所有command,并設(shè)置等待時(shí)間觸發(fā)下一次輪詢。DispatchOnceInnerLocked方法主要是檢查是否有pending event,有的話就進(jìn)行分發(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ù)輸入事件的類型進(jìn)行分發(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; .在該處理過(guò)程中,有一步是獲取響應(yīng)該事件的window target,主要是調(diào)用findFocusedWindowTargetsLocked完成。對(duì)此有三種情況,系統(tǒng)會(huì)認(rèn)為沒(méi)有ready的target:1)沒(méi)有找到focused window和focused application; 2) focused
25、window當(dāng)前正處于pause狀態(tài); 3)focused window還沒(méi)有處理完之前的事件。這些時(shí)候,handleTargetsNotReadyLocked方法就會(huì)被調(diào)用來(lái)處理這些異常情況。/ 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(shí)間超時(shí)之后,就會(huì)觸發(fā)ANR事件,并調(diào)用onANRLocked方法來(lái)做進(jìn)一步處理。再看觸摸事件的流程: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)部分與按鍵處理流程類似,對(duì)于異常情況最終
40、也調(diào)用handleTargetsNotReadyLocked方法來(lái)處理。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方法,會(huì)在command隊(duì)列中post一個(gè)command,在處理該command時(shí)會(huì)
42、調(diào)用關(guān)聯(lián)的doNotifyANRLockedInterruptible方法。void InputDispatcher:doNotifyANRLockedInterruptible( CommandEntry* commandEntry) . nsecs_t newTimeout = mPolicy->notifyANR( commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle, commandEntry->reason); .該方法會(huì)調(diào)用policy接口的notifyANR方法,其中通過(guò)
43、com_android_server_input_InputManagerService.cpp中的JNI接口調(diào)用InputManagerService的notifyANR方法,該方法也是一個(gè)wrapper method,最終實(shí)現(xiàn)是在InputMonitor類的notifyANR方法中。.frameworkbaseservicesjavacomandroidserverinputInputManagerService.java private long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHan
44、dle inputWindowHandle, String reason) return mWindowManagerCallbacks.notifyANR( inputApplicationHandle, inputWindowHandle, reason); 通過(guò)一系列調(diào)用,最終由ActivityManagerService彈出ANR對(duì)話框向用戶提示“應(yīng)用無(wú)響應(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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 河北工藝美術(shù)職業(yè)學(xué)院《傳統(tǒng)體育養(yǎng)生術(shù)》2023-2024學(xué)年第二學(xué)期期末試卷
- 浙江電力職業(yè)技術(shù)學(xué)院《工程力學(xué)(下)》2023-2024學(xué)年第二學(xué)期期末試卷
- 蘇科版數(shù)學(xué)七年級(jí)上冊(cè)4.3.1《用一元一次方程解決問(wèn)題》聽(tīng)評(píng)課記錄
- 北師大版道德與法治九年級(jí)上冊(cè)第3課 第1站《打開(kāi)財(cái)富之門(mén)》聽(tīng)課評(píng)課記錄
- 北師大的數(shù)學(xué)試卷
- 湖南汽車(chē)工程職業(yè)學(xué)院《圖像與視覺(jué)實(shí)驗(yàn)》2023-2024學(xué)年第二學(xué)期期末試卷
- 認(rèn)識(shí)壓強(qiáng)聽(tīng)評(píng)課記錄表
- 鹽城博物館施工方案
- 實(shí)驗(yàn)設(shè)計(jì)全解析
- 小學(xué)公開(kāi)課聽(tīng)評(píng)課記錄
- 2025版職業(yè)院校與企業(yè)合作育人合同3篇
- 自動(dòng)化設(shè)備項(xiàng)目評(píng)估報(bào)告模板范文
- 商標(biāo)法基礎(chǔ)知識(shí)
- 2025年高考物理一輪復(fù)習(xí)之機(jī)械振動(dòng)
- 《道路交通安全法》課件完整版
- 初中2025教學(xué)工作計(jì)劃
- 2024年度市政工程項(xiàng)目三方合作協(xié)議3篇
- 【大學(xué)課件】機(jī)電設(shè)備管理技術(shù)概論
- (2024)甘肅省公務(wù)員考試《行測(cè)》真題及答案解析
- 《STP營(yíng)銷戰(zhàn)略概述》課件
- 醫(yī)院醫(yī)務(wù)人員醫(yī)德考評(píng)標(biāo)準(zhǔn)
評(píng)論
0/150
提交評(píng)論