Skip to content

android ANR

cheyiliu edited this page Nov 17, 2014 · 33 revisions

本文内容

  • 由一个问题,引起对ANR相关code的学习。 对ANR形成一个全面的认识。

问题

  • 由于xx问题想改平台ANR的时间实验, 但在哪里改呢? 于是吭哧吭哧走起。。。

先找google得到some clue

  • appNotResponding

housy@housy-desktop:~/android-4.3.1-r2/frameworks/base$ ack appNotResponding core/java/android/app/IActivityController.aidl 60: int appNotResponding(String processName, int pid, String processStats);

cmds/am/src/com/android/commands/am/Am.java 961: public int appNotResponding(String processName, int pid, String processStats)

services/java/com/android/server/am/ActivityRecord.java 888: service.appNotResponding(anrApp, r, this, false, "keyDispatchingTimedOut");

services/java/com/android/server/am/ActivityManagerService.java 3251: final void appNotResponding(ProcessRecord app, ActivityRecord activity, 3359: int res = mController.appNotResponding(app.processName, app.pid, info.toString()); 7388: appNotResponding(proc, null, null, aboveSystem, "keyDispatchingTimedOut");

services/java/com/android/server/am/ActiveServices.java 1856: mAm.appNotResponding(proc, null, null, false, anrMessage);

services/java/com/android/server/am/BroadcastQueue.java 161: mService.appNotResponding(mApp, null, null, false, mAnnotation);


* http://stackoverflow.com/questions/17613709/application-not-responding-aosp   

// 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 * 1000000LL; // 5 sec


* http://blog.csdn.net/itachi85/article/details/6918761   
// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

* http://blog.csdn.net/ameyume/article/details/7038265

// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_TIMEOUT = 10*1000;

// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;


* ANR分析和实例  http://blog.csdn.net/duzc309/article/details/9363465




# 初步分析-1 (基于android-4.3.1-r2)
1. appNotResponding of ActivityManagerService, 这个函数调用时代表ANR已经发生,这个函数主要作了:输出Log,dump trace,发消息给主线程弹ANR对话框。
1. appNotResponding的可见性是包级的,那谁调用的他? 查找结果如下:
* ActiveServices.java, serviceTimeout [包级可见]
* BroadcastQueue.java, broadcastTimeoutLocked [包级可见]
* ActivityManagerService.java, inputDispatchingTimedOut [public]
* ActivityRecord.java, keyDispatchingTimedOut [public]



# 初步分析-2 (基于初步分析-1中的结论)
### ActiveServices.java, serviceTimeout [包级可见]
  1. 在执行service生命周期相关函数时调用并发送延迟消息, bumpServiceExecutingLocked ->mAm.mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);

  2. service相关函数调用结束调用并remove消息, serviceDoneExecutingLocked ->mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);

  3. 若调用timeout了,则ActivityManagerService收到消息并调用ActiveServices的serviceTimeout, 最终调到appNotResponding

  4. bumpServiceExecutingLocked,serviceDoneExecutingLocked粗粗看了下, 应该是和生命函数开始结束相关的,留作TODO吧

    
    
    
    

BroadcastQueue.java, broadcastTimeoutLocked [包级可见]

1. 开始处理广播 scheduleBroadcastsLocked->processNextBroadcast//BROADCAST_INTENT_MSG
2. 设置timeout processNextBroadcast->setBroadcastTimeoutLocked
  ->mHandler.sendMessageAtTime(msg, timeoutTime);
  ->broadcastTimeoutLocked(true);
3. 取消timeout processNextBroadcast->cancelBroadcastTimeoutLocked->mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
4. timeout broadcastTimeoutLocked->mHandler.post(new AppNotResponding(app, anrMessage));
  //AppNotResponding会掉用mService.appNotResponding(mApp, null, null, false, mAnnotation);

5. processNextBroadcast->broadcastTimeoutLocked(false);// forcibly finish this broadcast, 
  //if now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers), 
  //从comment看应该是个special case

ActivityManagerService.java, inputDispatchingTimedOut [public]

1. InputDispatcher.cpp, handleTargetsNotReadyLocked中mInputTargetWaitTimeoutTime的取值详见代码
         nsecs_t timeout;
         if (windowHandle != NULL) {
             timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
         } else if (applicationHandle != NULL) {
             timeout = applicationHandle->getDispatchingTimeout(
                     DEFAULT_INPUT_DISPATCHING_TIMEOUT);
         } else {
             timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
         }
       
         mInputTargetWaitTimeoutTime = currentTime + timeout;
  
         上面涉及的getDispatchingTimeout函数见本文最后 附录1 getDispatchingTimeout。
2. InputDispatcher.cpp, handleTargetsNotReadyLocked->onANRLocked// if currentTime >= mInputTargetWaitTimeoutTime
3. InputDispatcher.cpp, onANRLocked->doNotifyANRLockedInterruptible
4. InputDispatcher.cpp, doNotifyANRLockedInterruptible->nsecs_t newTimeout = mPolicy->notifyANR
  //mPolicy->notifyANR就是com_android_server_input_InputManagerService.cpp, notifyANR
5. com_android_server_input_InputManagerService.cpp, notifyANR-> env->CallLongMethod(mServiceObj,
             gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
             //本步骤完成从native callback to java layer
6. InputManagerService.java, notifyANR->mWindowManagerCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
  //InputManagerService.java, notifyANR是一个native callback
7. InputMonitor, notifyANR->ActivityManagerNative.getDefault().inputDispatchingTimedOut(
                     windowState.mSession.mPid, aboveSystem); // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut().

ActivityRecord.java, keyDispatchingTimedOut [public]

1. InputMonitor, notifyANR->appWindowToken.appToken.keyDispatchingTimedOut();
2. ActivityRecord的内部类static class Token extends IApplicationToken.Stub, 
  keyDispatchingTimedOut->activity.keyDispatchingTimedOut();
3. NOTE 1, 难怪有这样一个comment, // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut().
NOTE 2, 步骤1之前的流程同上一节 ActivityManagerService.java, inputDispatchingTimedOut [public]

到此学到了什么

  • 检测timeout可以在action前发送一个延迟消息,action按时处理完后则remove该消息,否则延迟的消息被收到视为timeout
  • appNotResponding of ActivityManagerService 是处理ANR弹框的地方
  • ANR有三种, service,broadcast 和 input dispatch
  • service ANR发生在相关的生命周期函数中,timeout值在ActiveServices.java

// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;

* broadcast timeout的值在 ActivityManagerService.java

// How long we allow a receiver to run before giving up on it static final int BROADCAST_FG_TIMEOUT = 101000;
static final int BROADCAST_BG_TIMEOUT = 60
1000;
used in http://androidxref.com/4.3_r2.1/xref/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java#1634
1634 mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
1635 mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);

* keyDispatchingTimedOut 的可能的取值范围是[附录1 可以进一步验证]
  1. InputDispatcher.cpp 65// Default input dispatching timeout if there is no focused application or paused window 66// from which to determine an appropriate dispatching timeout. 67const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec

  2. ActivityManagerService.java
    256 // How long we wait until we timeout on key dispatching. 257 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

259 // How long we wait until we timeout on key dispatching during instrumentation. 260 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000; //这个是小黑 一看就不像 有木有

  1. WindowManagerService.java // Default input dispatching timeout in nanoseconds. static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;



# 扩展
* 如何分析ANR问题
* input manager, activity mangager, window manager,找度娘和谷歌+http://androidxref.com   ,android发展到现在相信有很多人在分析



# 附录1 getDispatchingTimeout

getDispatchingTimeout xref: /frameworks/base/services/input/InputApplication.h inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { 54 return mInfo ? mInfo->dispatchingTimeout : defaultValue; 55 }

 xref: /frameworks/base/services/input/InputWindow.h 
175    inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
176        return mInfo ? mInfo->dispatchingTimeout : defaultValue;
177    }
178

前两者归结为一个关键字1 dispatchingTimeout H A D com_android_server_input_InputApplicationHandle.cpp 75 mInfo->dispatchingTimeout = env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos); int register_android_server_InputApplicationHandle(JNIEnv* env) { 138 int res = jniRegisterNativeMethods(env, "com/android/server/input/InputApplicationHandle", 139 gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); 140 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 141 142 jclass clazz; 143 FIND_CLASS(clazz, "com/android/server/input/InputApplicationHandle"); 144 145 GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, 146 "ptr", "I"); 147 148 GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz, 149 "name", "Ljava/lang/String;"); 150 151 GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos, 152 clazz, 153 "dispatchingTimeoutNanos", "J"); 154 155 return 0; 156}

					InputApplicationHandle.java, dispatchingTimeoutNanos



	H A D	com_android_server_input_InputWindowHandle.cpp	114 mInfo->dispatchingTimeout = env->GetLongField(obj,
			int register_android_server_InputWindowHandle(JNIEnv* env) {
			224    int res = jniRegisterNativeMethods(env, "com/android/server/input/InputWindowHandle",
			225            gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
			226    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
			227
			228    jclass clazz;
			229    FIND_CLASS(clazz, "com/android/server/input/InputWindowHandle");
			230
			231    GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
			232            "ptr", "I");
			233
			234    GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle,
			235            clazz,
			236            "inputApplicationHandle", "Lcom/android/server/input/InputApplicationHandle;");
			237
			238    GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz,
			239            "inputChannel", "Landroid/view/InputChannel;");
			240
			241    GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
			242            "name", "Ljava/lang/String;");
			243
			244    GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
			245            "layoutParamsFlags", "I");
			246
			247    GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
			248            "layoutParamsType", "I");
			249
			250    GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
			251            "dispatchingTimeoutNanos", "J");


					InputWindowHandle.java dispatchingTimeoutNanos

前两者归结为一个关键字2 dispatchingTimeoutNanos H A D FakeWindowImpl.java 57 mApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; 67 mWindowHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; H A D DragState.java 109 mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS 119 mDragWindowHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;

		WindowManagerService.java 
			    // Default input dispatching timeout in nanoseconds.
			    static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;	
			
			!!! [this is DONE] !!!


	H A D	InputMonitor.java	170 inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
		H A D	WindowState.java	685 public long getInputDispatchingTimeoutNanos() { method in class:WindowState 
			    public long getInputDispatchingTimeoutNanos() {
				return mAppToken != null
					? mAppToken.inputDispatchingTimeoutNanos
					: WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
			    }
			!!! [this is DONE] !!!


	403 handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos;
		H A D	WindowManagerService.java	3332 long inputDispatchingTimeoutNanos;
		3334 inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
		3337 inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
		3347 atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;

			WindowManagerService.java 
				    // Default input dispatching timeout in nanoseconds.
				    static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
				!!! [this is DONE] !!!
			

			getKeyDispatchingTimeout					
				H A D	ActivityRecord.java	301 @Override public long getKeyDispatchingTimeout() throws RemoteException { method in class:ActivityRecord.Token
				304 return activity.getKeyDispatchingTimeout();
				880 public long getKeyDispatchingTimeout() { method in class:ActivityRecord 
					    /** Returns the key dispatching timeout for this application token. */
					    public long getKeyDispatchingTimeout() {
						synchronized(service) {
						    ActivityRecord r = getWaitingHistoryRecordLocked();
						    if (r != null && r.app != null
							    && (r.app.instrumentationClass != null || r.app.usingWrapper)) {
							return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
						    }

						    return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
						}
					    }
					!!! [this is DONE] !!!
Clone this wiki locally