一、概述
ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。
那么哪些场景会造成ANR呢?
Service Timeout:服务在20s内未执行完成; BroadcastQueue Timeout:比如前台广播在10s内执行完成 ContentProvider Timeout:内容提供者执行超时 inputDispatching Timeout: 输入事件分发超时5s,包括按键分发事件的超时。
二、ANR触发时机
2.1 Service Timeout
Service Timeout触发时机,简单说就是AMS中的mHandler
收到SERVICE_TIMEOUT_MSG
消息时触发。
在前面文章startService流程分析 详细介绍Service启动流程,在Service所在进程attach到system_server进程的过程中会调用realStartServiceLocked()
方法
2.1.1 realStartServiceLocked
[-> ActiveServices.java]
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ...
} <span class="hljs-keyword">catch (DeadObjectException e) {
...
} <span class="hljs-keyword">finally {
<span class="hljs-keyword">if (!created) {
<span class="hljs-comment">//当service启动完毕,则remove SERVICE_TIMEOUT_MSG消息【见小节2.1.3】
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
...
}
}
}
2.1.2 bumpServiceExecutingLocked
该方法的主要工作发送delay消息(SERVICE_TIMEOUT_MSG)
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { ... scheduleServiceTimeoutLocked(r.app); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } long now = SystemClock.uptimeMillis(); Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc;
对于前台服务,则超时为SERVICE_TIMEOUT
,即timeout=20s; 对于后台服务,则超时为SERVICE_BACKGROUND_TIMEOUT
,即timeout=200s;
2.1.3 serviceDoneExecutingLocked
该方法的主要工作是当service启动完成,则移除service Timeout消息。
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { ... if (r.executeNesting <= 0) { if (r.app != null) { r.app.execServicesFg = false; r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) {
2.1.4 SERVICE_TIMEOUT_MSG
到此不难理解,当SERVICE_TIMEOUT_MSG
消息成功发送时,则AMS中的mHandler
收到该消息则触发调用serviceTimeout
。
final class MainHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { ...
2.1.5 serviceTimeout
[-> ActiveServices.java]
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
<span class="hljs-keyword">synchronized(mAm) {
<span class="hljs-keyword">if (proc.executingServices.size() == <span class="hljs-number">0 || proc.thread == <span class="hljs-keyword">null) {
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">final <span class="hljs-keyword">long now = SystemClock.uptimeMillis();
<span class="hljs-keyword">final <span class="hljs-keyword">long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = <span class="hljs-keyword">null;
<span class="hljs-keyword">long nextTime = <span class="hljs-number">0;
<span class="hljs-keyword">for (<span class="hljs-keyword">int i=proc.executingServices.size()-<span class="hljs-number">1; i>=<span class="hljs-number">0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
<span class="hljs-keyword">if (sr.executingStart < maxTime) {
timeout = sr;
<span class="hljs-keyword">break;
}
<span class="hljs-keyword">if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
<span class="hljs-keyword">if (timeout != <span class="hljs-keyword">null && mAm.mLruProcesses.contains(proc)) {
Slog.w(TAG, <span class="hljs-string">"Timeout executing service: " + timeout);
StringWriter sw = <span class="hljs-keyword">new StringWriter();
PrintWriter pw = <span class="hljs-keyword">new FastPrintWriter(sw, <span class="hljs-keyword">false, <span class="hljs-number">1024);
pw.println(timeout);
timeout.dump(pw, <span class="hljs-string">" ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
anrMessage = <span class="hljs-string">"executing service " + timeout.shortName;
}
}
<span class="hljs-keyword">if (anrMessage != <span class="hljs-keyword">null) {
<span class="hljs-comment">//当存在timeout的service,则执行appNotResponding【见小节3.1】
mAm.appNotResponding(proc, <span class="hljs-keyword">null, <span class="hljs-keyword">null, <span class="hljs-keyword">false, anrMessage);
}
}
其中anrMessage的内容为”executing service [发送超时serviceRecord信息]”;
2.2 BroadcastQueue Timeout
BroadcastQueue Timeout触发时机,简单说就是BroadcastQueue中的mHandler
收到BROADCAST_TIMEOUT_MSG
消息时触发。
在前面文章Android Broadcast广播机制分析 详细介绍广播启动流程,在发送广播过程中会执行scheduleBroadcastsLocked
方法来处理相关的广播,然后会调用到processNextBroadcast
方法来处理下一条广播。
processNextBroadcast执行过程分4步骤:
step1. 处理并行广播 step2. 处理当前有序广播 step3. 获取下条有序广播 step4. 处理下条有序广播
2.2.1 processNextBroadcast
[-> BroadcastQueue.java]
final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { ...
<span class="hljs-comment">//step 3: 获取下条有序广播
r.receiverTime = SystemClock.uptimeMillis();
<span class="hljs-keyword">if (!mPendingBroadcastTimeoutMessage) {
<span class="hljs-keyword">long timeoutTime = r.receiverTime + mTimeoutPeriod;
<span class="hljs-comment">//设置广播超时时间,发送BROADCAST_TIMEOUT_MSG【见小节2.2.2】
setBroadcastTimeoutLocked(timeoutTime);
}
...
}
}
对于广播超时处理时机:
首先在step3的过程中setBroadcastTimeoutLocked(timeoutTime) 设置超时广播消息; 然后在step2根据广播处理情况来处理:
当广播接收者等待时间过长,则调用broadcastTimeoutLocked(false); 当,cancelBroadcastTimeoutLocked
2.2.2 setBroadcastTimeoutLocked
final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; } }
设置定时广播BROADCAST_TIMEOUT_MSG,即当前往后推mTimeoutPeriod时间广播还没处理完毕,则进入广播超时流程。
对于前台广播,则超时为BROADCAST_FG_TIMEOUT
,即timeout=10s; 对于后台广播,则超时为BROADCAST_BG_TIMEOUT
,即timeout=60s。
2.2.3 cancelBroadcastTimeoutLocked
final void cancelBroadcastTimeoutLocked() { if (mPendingBroadcastTimeoutMessage) { mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); mPendingBroadcastTimeoutMessage = false; } }
移除广播超时消息BROADCAST_TIMEOUT_MSG
2.2.4 BROADCAST_TIMEOUT_MSG
到此不难理解,当BROADCAST_TIMEOUT_MSG
消息成功发送时,则AMS中的mHandler
收到该消息则触发调用serviceTimeout
。
private final class BroadcastHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_TIMEOUT_MSG: { synchronized (mService) {
2.2.5 broadcastTimeoutLocked
[-> BroadcastRecord.java]
final void broadcastTimeoutLocked(boolean fromMsg) { if (fromMsg) { mPendingBroadcastTimeoutMessage = false; }
<span class="hljs-keyword">if (mOrderedBroadcasts.size() == <span class="hljs-number">0) {
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">long now = SystemClock.uptimeMillis();
BroadcastRecord r = mOrderedBroadcasts.get(<span class="hljs-number">0);
<span class="hljs-keyword">if (fromMsg) {
<span class="hljs-keyword">if (mService.mDidDexOpt) {
<span class="hljs-comment">//延迟timeouts直到dexopt结束
mService.mDidDexOpt = <span class="hljs-keyword">false;
<span class="hljs-keyword">long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">if (!mService.mProcessesReady) {
<span class="hljs-comment">//当系统还没有准备就绪时,广播处理流程中不存在广播超时
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">long timeoutTime = r.receiverTime + mTimeoutPeriod;
<span class="hljs-keyword">if (timeoutTime > now) {
<span class="hljs-comment">//过早的timeout,重新设置广播超时
setBroadcastTimeoutLocked(timeoutTime);
<span class="hljs-keyword">return;
}
}
BroadcastRecord br = mOrderedBroadcasts.get(<span class="hljs-number">0);
<span class="hljs-keyword">if (br.state == BroadcastRecord.WAITING_SERVICES) {
<span class="hljs-comment">//广播已经处理完成,但需要等待已启动service执行完成。当等待足够时间,则处理下一条广播。
br.curComponent = <span class="hljs-keyword">null;
br.state = BroadcastRecord.IDLE;
processNextBroadcast(<span class="hljs-keyword">false);
<span class="hljs-keyword">return;
}
r.receiverTime = now;
<span class="hljs-comment">//当前BroadcastRecord的anr次数执行加1操作
r.anrCount++;
<span class="hljs-keyword">if (r.nextReceiver <= <span class="hljs-number">0) {
<span class="hljs-keyword">return;
}
ProcessRecord app = <span class="hljs-keyword">null;
String anrMessage = <span class="hljs-keyword">null;
Object curReceiver = r.receivers.get(r.nextReceiver-<span class="hljs-number">1);
<span class="hljs-comment">//根据情况记录广播接收者丢弃的EventLog
logBroadcastReceiverDiscardLocked(r);
<span class="hljs-keyword">if (curReceiver <span class="hljs-keyword">instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
<span class="hljs-keyword">if (bf.receiverList.pid != <span class="hljs-number">0
&& bf.receiverList.pid != ActivityManagerService.MY_PID) {
<span class="hljs-keyword">synchronized (mService.mPidsSelfLocked) {
app = mService.mPidsSelfLocked.get(
bf.receiverList.pid);
}
}
} <span class="hljs-keyword">else {
app = r.curApp;
}
<span class="hljs-keyword">if (app != <span class="hljs-keyword">null) {
anrMessage = <span class="hljs-string">"Broadcast of " + r.intent.toString();
}
<span class="hljs-keyword">if (mPendingBroadcast == r) {
mPendingBroadcast = <span class="hljs-keyword">null;
}
<span class="hljs-comment">//继续移动到下一个广播接收者
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, <span class="hljs-keyword">false);
scheduleBroadcastsLocked();
<span class="hljs-keyword">if (anrMessage != <span class="hljs-keyword">null) {
<span class="hljs-comment">//【见小节2.2.6】
mHandler.post(<span class="hljs-keyword">new AppNotResponding(app, anrMessage));
}
}
2.2.6 AppNotResponding
[-> BroadcastQueue.java]
private final class AppNotResponding implements Runnable { ... public void run() {
2.3 ContentProvider Timeout
2.3.1 AMS.appNotRespondingViaProvider
public void appNotRespondingViaProvider(IBinder connection) { enforceCallingPermission( android.Manifest.permission.REMOVE_TASKS, "appNotRespondingViaProvider()");
<span class="hljs-keyword">final ContentProviderConnection conn = (ContentProviderConnection) connection;
<span class="hljs-keyword">if (conn == <span class="hljs-keyword">null) {
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">final ProcessRecord host = conn.provider.proc;
<span class="hljs-comment">//无法找到provider所处的进程
<span class="hljs-keyword">if (host == <span class="hljs-keyword">null) {
<span class="hljs-keyword">return;
}
<span class="hljs-keyword">final <span class="hljs-keyword">long token = Binder.clearCallingIdentity();
<span class="hljs-keyword">try {
<span class="hljs-comment">//【见小节3.1】
appNotResponding(host, <span class="hljs-keyword">null, <span class="hljs-keyword">null, <span class="hljs-keyword">false, <span class="hljs-string">"ContentProvider not responding");
} <span class="hljs-keyword">finally {
Binder.restoreCallingIdentity(token);
}
}
Timeout时间20s
调用链:
ContentProviderClient.NotRespondingRunnable.run
ContextImpl.ApplicationContentResolver.appNotRespondingViaProvider ActivityThread.appNotRespondingViaProvider AMP.appNotRespondingViaProvider AMS.appNotRespondingViaProvider
在native层InputDispatcher.cpp中经过层层调用,此处先省略过程,后续再展开,从native层com_android_server_input_InputManagerService调用到java层InputManagerService。
2.4.1 IMS.notifyANR
[-> InputManagerService.java]
private long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason) {
mWindowManagerCallbacks为InputMonitor对象
2.4.2 notifyANR
[-> InputMonitor.java]
public long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason) { AppWindowToken appWindowToken = null; WindowState windowState = null; boolean aboveSystem = false; synchronized (mService.mWindowMap) { if (inputWindowHandle != null) { windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { appWindowToken = windowState.mAppToken; } } if (appWindowToken == null && inputApplicationHandle != null) { appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken; }
<span class="hljs-keyword">if (appWindowToken != <span class="hljs-keyword">null && appWindowToken.appToken != <span class="hljs-keyword">null) {
<span class="hljs-comment">//【见小节2.5.1】
<span class="hljs-keyword">boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
<span class="hljs-keyword">if (! abort) {
<span class="hljs-keyword">return appWindowToken.inputDispatchingTimeoutNanos;
}
} <span class="hljs-keyword">else <span class="hljs-keyword">if (windowState != <span class="hljs-keyword">null) {
<span class="hljs-comment">//AMP经过binder,最终调用到AMS【见小节2.4.3】
<span class="hljs-keyword">long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
<span class="hljs-keyword">if (timeout >= <span class="hljs-number">0) {
<span class="hljs-keyword">return timeout * <span class="hljs-number">1000000L; <span class="hljs-comment">//转化为纳秒
}
}
<span class="hljs-keyword">return <span class="hljs-number">0;
}
public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { ... ProcessRecord proc; long timeout; synchronized (this) { synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid);
<span class="hljs-keyword">return timeout;
}
inputDispatching的超时为KEY_DISPATCHING_TIMEOUT
,即timeout = 5s
public boolean inputDispatchingTimedOut(final ProcessRecord proc, final ActivityRecord activity, final ActivityRecord parent, final boolean aboveSystem, String reason) { ... final String annotation; if (reason == null) { annotation = "Input dispatching timed out"; } else { annotation = "Input dispatching timed out (" + reason + ")"; }
<span class="hljs-keyword">if (proc != <span class="hljs-keyword">null) {
...
mHandler.post(<span class="hljs-keyword">new Runnable() {
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">run<span class="hljs-params">() {
<span class="hljs-comment">//【见小节3.1】
appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
<span class="hljs-keyword">return <span class="hljs-keyword">true;
}
调用链:
InputManagerService.notifyANR
InputMonitor.notifyANR
AMP.inputDispatchingTimedOut AMS.inputDispatchingTimedOut
2.5 keyDispatching Timeout
keyDispatching timout与inputDispatching Timeout流畅基本一致。
调用链:
InputManagerService.notifyANR
InputMonitor.notifyANR
ActivityRecord.Token.keyDispatchingTimedOut AMS.inputDispatchingTimedOut
Token.keyDispatchingTimedOut
[-> ActivityRecord.java]
final class ActivityRecord {
static class Token extends IApplicationToken.Stub { public boolean keyDispatchingTimedOut(String reason) { ActivityRecord r; ActivityRecord anrActivity; ProcessRecord anrApp; synchronized (mService) { r = tokenToActivityRecordLocked(this); if (r == null) { return false; } anrActivity = r.getWaitingHistoryRecordLocked(); anrApp = r != null ? r.app : null; } return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason); } ... } }
对于keyDispatching Timeout的ANR,当触发该类型ANR时,如果不再有输入事件,则不会弹出ANR对话框;只有在下一次input事件产生后5s才弹出ANR提示框。
三、ANR工作
3.1 appNotResponding
[-> ActivityManagerService.java]
final void appNotResponding(ProcessRecord app, ActivityRecord activity, ActivityRecord parent, boolean aboveSystem, final String annotation) { ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
<span class="hljs-keyword">if (mController != <span class="hljs-keyword">null) {
<span class="hljs-keyword">try {
<span class="hljs-comment">// 0 == continue, -1 = kill process immediately
<span class="hljs-keyword">int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation);
<span class="hljs-keyword">if (res < <span class="hljs-number">0 && app.pid != MY_PID) {
app.kill(<span class="hljs-string">"anr", <span class="hljs-keyword">true);
}
} <span class="hljs-keyword">catch (RemoteException e) {
mController = <span class="hljs-keyword">null;
Watchdog.getInstance().setActivityController(<span class="hljs-keyword">null);
}
}
<span class="hljs-keyword">long anrTime = SystemClock.uptimeMillis();
<span class="hljs-keyword">if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
}
<span class="hljs-keyword">synchronized (<span class="hljs-keyword">this) {
<span class="hljs-comment">// PowerManager.reboot() 会阻塞很长时间,因此忽略关机时的ANR
<span class="hljs-keyword">if (mShuttingDown) {
Slog.i(TAG, <span class="hljs-string">"During shutdown skipping ANR: " + app + <span class="hljs-string">" " + annotation);
<span class="hljs-keyword">return;
} <span class="hljs-keyword">else <span class="hljs-keyword">if (app.notResponding) {
Slog.i(TAG, <span class="hljs-string">"Skipping duplicate ANR: " + app + <span class="hljs-string">" " + annotation);
<span class="hljs-keyword">return;
} <span class="hljs-keyword">else <span class="hljs-keyword">if (app.crashing) {
Slog.i(TAG, <span class="hljs-string">"Crashing app skipping ANR: " + app + <span class="hljs-string">" " + annotation);
<span class="hljs-keyword">return;
}
app.notResponding = <span class="hljs-keyword">true;
<span class="hljs-comment">//记录ANR
EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
app.processName, app.info.flags, annotation);
<span class="hljs-comment">// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(app.pid);
<span class="hljs-keyword">int parentPid = app.pid;
<span class="hljs-keyword">if (parent != <span class="hljs-keyword">null && parent.app != <span class="hljs-keyword">null && parent.app.pid > <span class="hljs-number">0) parentPid = parent.app.pid;
<span class="hljs-keyword">if (parentPid != app.pid) firstPids.add(parentPid);
<span class="hljs-keyword">if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
<span class="hljs-keyword">for (<span class="hljs-keyword">int i = mLruProcesses.size() - <span class="hljs-number">1; i >= <span class="hljs-number">0; i--) {
ProcessRecord r = mLruProcesses.get(i);
<span class="hljs-keyword">if (r != <span class="hljs-keyword">null && r.thread != <span class="hljs-keyword">null) {
<span class="hljs-keyword">int pid = r.pid;
<span class="hljs-keyword">if (pid > <span class="hljs-number">0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
<span class="hljs-keyword">if (r.persistent) {
firstPids.add(pid);
} <span class="hljs-keyword">else {
lastPids.put(pid, Boolean.TRUE);
}
}
}
}
}
<span class="hljs-comment">//输出ANR到main log.
StringBuilder info = <span class="hljs-keyword">new StringBuilder();
info.setLength(<span class="hljs-number">0);
info.append(<span class="hljs-string">"ANR in ").append(app.processName);
<span class="hljs-keyword">if (activity != <span class="hljs-keyword">null && activity.shortComponentName != <span class="hljs-keyword">null) {
info.append(<span class="hljs-string">" (").append(activity.shortComponentName).append(<span class="hljs-string">")");
}
info.append(<span class="hljs-string">"\n");
info.append(<span class="hljs-string">"PID: ").append(app.pid).append(<span class="hljs-string">"\n");
<span class="hljs-keyword">if (annotation != <span class="hljs-keyword">null) {
info.append(<span class="hljs-string">"Reason: ").append(annotation).append(<span class="hljs-string">"\n");
}
<span class="hljs-keyword">if (parent != <span class="hljs-keyword">null && parent != activity) {
info.append(<span class="hljs-string">"Parent: ").append(parent.shortComponentName).append(<span class="hljs-string">"\n");
}
<span class="hljs-keyword">final ProcessCpuTracker processCpuTracker = <span class="hljs-keyword">new ProcessCpuTracker(<span class="hljs-keyword">true);
<span class="hljs-comment">//dump栈信息
File tracesFile = dumpStackTraces(<span class="hljs-keyword">true, firstPids, processCpuTracker, lastPids,
NATIVE_STACKS_OF_INTEREST);
String cpuInfo = <span class="hljs-keyword">null;
<span class="hljs-keyword">if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
<span class="hljs-keyword">synchronized (mProcessCpuTracker) {
<span class="hljs-comment">//输出各个进程的CPU使用情况
cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
}
<span class="hljs-comment">//输出CPU负载
info.append(processCpuTracker.printCurrentLoad());
info.append(cpuInfo);
}
info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
<span class="hljs-keyword">if (tracesFile == <span class="hljs-keyword">null) {
<span class="hljs-comment">//发送signal 3来dump栈信息
Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
}
<span class="hljs-comment">//将anr信息添加到dropbox
addErrorToDropBox(<span class="hljs-string">"anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, <span class="hljs-keyword">null);
<span class="hljs-keyword">if (mController != <span class="hljs-keyword">null) {
<span class="hljs-keyword">try {
<span class="hljs-comment">// 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
<span class="hljs-keyword">int res = mController.appNotResponding(app.processName, app.pid, info.toString());
<span class="hljs-keyword">if (res != <span class="hljs-number">0) {
<span class="hljs-keyword">if (res < <span class="hljs-number">0 && app.pid != MY_PID) {
app.kill(<span class="hljs-string">"anr", <span class="hljs-keyword">true);
} <span class="hljs-keyword">else {
<span class="hljs-keyword">synchronized (<span class="hljs-keyword">this) {
mServices.scheduleServiceTimeoutLocked(app);
}
}
<span class="hljs-keyword">return;
}
} <span class="hljs-keyword">catch (RemoteException e) {
mController = <span class="hljs-keyword">null;
Watchdog.getInstance().setActivityController(<span class="hljs-keyword">null);
}
}
<span class="hljs-keyword">boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, <span class="hljs-number">0) != <span class="hljs-number">0;
<span class="hljs-keyword">synchronized (<span class="hljs-keyword">this) {
mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
<span class="hljs-keyword">if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
app.kill(<span class="hljs-string">"bg anr", <span class="hljs-keyword">true);
<span class="hljs-keyword">return;
}
<span class="hljs-comment">// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(app,
activity != <span class="hljs-keyword">null ? activity.shortComponentName : <span class="hljs-keyword">null,
annotation != <span class="hljs-keyword">null ? <span class="hljs-string">"ANR " + annotation : <span class="hljs-string">"ANR",
info.toString());
<span class="hljs-comment">//弹出ANR对话框
Message msg = Message.obtain();
HashMap<String, Object> map = <span class="hljs-keyword">new HashMap<String, Object>();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
msg.arg1 = aboveSystem ? <span class="hljs-number">1 : <span class="hljs-number">0;
map.put(<span class="hljs-string">"app", app);
<span class="hljs-keyword">if (activity != <span class="hljs-keyword">null) {
map.put(<span class="hljs-string">"activity", activity);
}
mUiHandler.sendMessage(msg);
}
}
主要发送ANR, 则会输出
各个进程的CPU使用情况; CPU负载; IOWait; traces文件
四、其他
导致ANR常见情形:
I/O阻塞 网络阻塞; onReceiver执行时间超过10s; 多线程死锁
避免ANR:
UI线程尽量只做跟UI相关的工作 耗时的工作()比如数据库操作,I/O,网络操作),采用单独的工作线程处理 用Handler来处理UIthread和工作thread的交互
UI线程,例如:
Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc Mainthread handler: handleMessage(), post*(runnable r), etc …
ANR分析:需要关注CPU/IO,trace死锁等数据。
失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。
</div>
<p class="postfoot">
posted on <span id="post-date">2016-07-29 14:35</span> <a href="https://www.cnblogs.com/android-blogs/">Sun‘刺眼的博客</a> 阅读(<span id="post_view_count">18367</span>) 评论(<span id="post_comment_count">0</span>) <a href="https://i.cnblogs.com/EditPosts.aspx?postid=5718302" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(5718302);return false;">收藏</a>
</p>
</div>