版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android ANR代码分析(技术文档)内容目录1 什么是ANR52 ANR代码执行流程52.1 事件分发超时ANR52.2 启动输入分发线程(InputDispatcherThread)52.3 输入事件的分发流程72.4 ANR处理流程132.5 针对Service超时的ANR处理流程172.6 针对Broadcast超时的ANR处理流程182.7 ANR超时时间222.8 序列图241 什么是ANRANR是“Application Not Responding”的缩写,即“应用程序无响应”。在Android中,ActivityManagerService(简称AMS)和WindowMa
2、nagerService(简称WMS)会监测应用程序的响应时间,如果应用程序主线程(即UI线程)在超时时间内对输入事件没有处理完毕,或者对特定操作没有执行完毕,就会出现ANR。对于输入事件没有处理完毕产生的ANR,Android会显示一个对话框,提示用户当前应用程序没有响应,用户可以选择继续等待或者关闭这个应用程序(也就是杀掉这个应用程序的进程)。2 ANR代码执行流程本文档所有分析均基于Android 4.4原生代码。2.1 事件分发超时ANR响应事件超时的ANR流程大概如下,在系统输入管理服务进程(InputManagerService)中有一个单独线程(InputDispatcherTh
3、read)会专门管理输入事件分发,在该线程处理输入事件的过程中,会调用InputDispatcher不断的检测处理过程是否超时,一旦超时,会通过一系列的回调通知WMS的notifyANR函数,最终会触发AMS中mHandler对象里的SHOW_NOT_RESPONDING_MSG这个事件并在AMS中进行相应处理,此时界面上就会显示系统ANR提示对话框。2.2 启动输入分发线程(InputDispatcherThread)InputDispatcherThread作为输入事件分发处理的核心线程,会随系统服务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在启动时会调用nativeStart方法,其中会启动InputDispatcherThread线程。具体代码在JNI方法nativeInit和nativeStart中实现。.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中调用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构造方法中,会新建
10、InputDispatcher对象,该对象会做为一个核心对象来处理所有输入事件分发逻辑。在initialize方法中,分发线程对象被建立,并在start方法中启动InputDispatcherThread线程。2.3 输入事件的分发流程输入事件的分发逻辑主要是在InputDispatcher类中实现的。先看一下InputDispatcherThread线程类:.frameworkbaseservicesinputInputDispatcher.cppInputDispatcherThread:InputDispatcherThread(const sp<InputDispatcherIn
11、terface>& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) bool InputDispatcherThread:threadLoop() mDispatcher->dispatchOnce(); return true;该线程的loop方法中,只执行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项,没有的话会调用dispatchOnceInnerLocked方法做进一步处理,有的话则依序处理队列中所有command,并设置等待时间触发下一次轮询。DispatchOnceInnerLocked方法主要是检查是否有pending event,有的话就进行分发
15、处理,下面具体关注与ANR相关的部分代码。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; 根据输入事件的类型进行分发处理,和ANR相关
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; .在该处理过程中,有一步是获取响应该事件的window target,主要是调用findFocusedWindowTargetsLocked完成。对此有三种情况,系统会认为没有ready的target:1)没有找到focused window和focused application; 2) focused
25、window当前正处于pause状态; 3)focused window还没有处理完之前的事件。这些时候,handleTargetsNotReadyLocked方法就会被调用来处理这些异常情况。/ 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; 当等待时间超时之后,就会触发ANR事件,并调用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相关部分与按键处理流程类似,对于异常情况最终
40、也调用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、调用关联的doNotifyANRLockedInterruptible方法。void InputDispatcher:doNotifyANRLockedInterruptible( CommandEntry* commandEntry) . nsecs_t newTimeout = mPolicy->notifyANR( commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle, commandEntry->reason); .该方法会调用policy接口的notifyANR方法,其中通过
43、com_android_server_input_InputManagerService.cpp中的JNI接口调用InputManagerService的notifyANR方法,该方法也是一个wrapper method,最终实现是在InputMonitor类的notifyANR方法中。.frameworkbaseservicesjavacomandroidserverinputInputManagerService.java private long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHan
44、dle inputWindowHandle, String reason) return mWindowManagerCallbacks.notifyANR( inputApplicationHandle, inputWindowHandle, reason); 通过一系列调用,最终由ActivityManagerService弹出ANR对话框向用户提示“应用无响应”信息。.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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 健身房砌墙施工合同
- 幼儿园景观照明电工招聘
- 保健分公司管理手册
- 知识产权侵权行为处罚办法
- 商业促销设备短期租赁合同
- 旧城改造项目密封条样本
- 建筑咨询项目经理施工协议
- 商铺自动门施工合同
- 剧院音响租赁合同
- 环保信息化管理行动计划
- 职业技能大赛-鸿蒙移动应用开发赛初赛理论知识考试及答案
- 锅炉应急预案演练方案
- 2024山东高速集团限公司招聘367人高频难、易错点500题模拟试题附带答案详解
- 中国航天发展史主题班会 课件
- 【人教版】《劳动教育》二下 劳动项目一 洗头 课件
- 第三单元长方形和正方形(单元测试)-2024-2025学年三年级上册数学苏教版
- 灯展合同范本
- 【课件】城镇与乡村课件2024-2025学年人教版地理七年级上册
- 北京市历年中考语文现代文之议论文阅读30篇(含答案)(2003-2023)
- 四川省绵阳市2025届高三数学上学期第一次诊断性考试试题文含解析
- 一 《改造我们的学习》(同步练习)解析版
评论
0/150
提交评论