Hopefully get rid of some ANRs.
Don't hold the activity manager lock the entire time we are processing an ANR,
which often causes us to cause a second ANR as someone else calls into the
activity manager and gets blocked.
Change-Id: Ife4db82b12d6f4378ac2705bd6f60beb1244a1e6
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cd2d3e3..3bd65cb 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4757,32 +4757,46 @@
return tracesFile;
}
- final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
+ final void appNotResponding(ProcessRecord app, HistoryRecord activity,
HistoryRecord parent, final String annotation) {
- // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
- if (mShuttingDown || app.notResponding || app.crashing) {
- return;
- }
-
- // Log the ANR to the event log.
- EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
- annotation);
-
- // Dump thread traces as quickly as we can, starting with "interesting" processes.
ArrayList<Integer> pids = new ArrayList<Integer>(20);
- pids.add(app.pid);
+
+ synchronized (this) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mShuttingDown) {
+ Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
+ return;
+ } else if (app.notResponding) {
+ Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
+ return;
+ } else if (app.crashing) {
+ Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
+ return;
+ }
+
+ // In case we come through here for the same app before completing
+ // this one, mark as anring now so we will bail out.
+ app.notResponding = true;
- int parentPid = app.pid;
- if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
- if (parentPid != app.pid) pids.add(parentPid);
+ // Log the ANR to the event log.
+ EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
+ annotation);
- if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
+ // Dump thread traces as quickly as we can, starting with "interesting" processes.
+ pids.add(app.pid);
+
+ int parentPid = app.pid;
+ if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
+ if (parentPid != app.pid) pids.add(parentPid);
+
+ if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- if (r != null && r.thread != null) {
- int pid = r.pid;
- if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r != null && r.thread != null) {
+ int pid = r.pid;
+ if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
+ }
}
}
@@ -4806,7 +4820,9 @@
String cpuInfo = null;
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
- synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
+ synchronized (mProcessStatsThread) {
+ cpuInfo = mProcessStats.printCurrentState();
+ }
info.append(cpuInfo);
}
@@ -4834,29 +4850,31 @@
// Unless configured otherwise, swallow ANRs in background processes & kill the process.
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
- if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
- Process.killProcess(app.pid);
- return;
+
+ synchronized (this) {
+ if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
+ Process.killProcess(app.pid);
+ return;
+ }
+
+ // Set the app's notResponding state, and look up the errorReportReceiver
+ makeAppNotRespondingLocked(app,
+ activity != null ? activity.shortComponentName : null,
+ annotation != null ? "ANR " + annotation : "ANR",
+ info.toString());
+
+ // Bring up the infamous App Not Responding dialog
+ Message msg = Message.obtain();
+ HashMap map = new HashMap();
+ msg.what = SHOW_NOT_RESPONDING_MSG;
+ msg.obj = map;
+ map.put("app", app);
+ if (activity != null) {
+ map.put("activity", activity);
+ }
+
+ mHandler.sendMessage(msg);
}
-
- // Set the app's notResponding state, and look up the errorReportReceiver
- makeAppNotRespondingLocked(app,
- activity != null ? activity.shortComponentName : null,
- annotation != null ? "ANR " + annotation : "ANR",
- info.toString());
-
- // Bring up the infamous App Not Responding dialog
- Message msg = Message.obtain();
- HashMap map = new HashMap();
- msg.what = SHOW_NOT_RESPONDING_MSG;
- msg.obj = map;
- map.put("app", app);
- if (activity != null) {
- map.put("activity", activity);
- }
-
- mHandler.sendMessage(msg);
- return;
}
private final void decPersistentCountLocked(ProcessRecord app)
@@ -11855,6 +11873,8 @@
}
void serviceTimeout(ProcessRecord proc) {
+ String anrMessage = null;
+
synchronized(this) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
@@ -11875,13 +11895,17 @@
}
if (timeout != null && mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
- appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
+ anrMessage = "Executing service " + timeout.shortName;
} else {
Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
}
}
+
+ if (anrMessage != null) {
+ appNotResponding(proc, null, null, anrMessage);
+ }
}
// =========================================================
@@ -12680,6 +12704,9 @@
}
private final void broadcastTimeout() {
+ ProcessRecord app = null;
+ String anrMessage = null;
+
synchronized (this) {
if (mOrderedBroadcasts.size() == 0) {
return;
@@ -12705,8 +12732,6 @@
return;
}
- ProcessRecord app = null;
-
Object curReceiver = r.receivers.get(r.nextReceiver-1);
Slog.w(TAG, "Receiver during timeout: " + curReceiver);
logBroadcastReceiverDiscard(r);
@@ -12724,7 +12749,7 @@
}
if (app != null) {
- appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
+ anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
@@ -12736,6 +12761,10 @@
r.resultExtras, r.resultAbort, true);
scheduleBroadcastsLocked();
}
+
+ if (anrMessage != null) {
+ appNotResponding(app, null, null, anrMessage);
+ }
}
private final void processCurBroadcastLocked(BroadcastRecord r,
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 7d7247c..dca7a99 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -458,8 +458,10 @@
}
public boolean keyDispatchingTimedOut() {
+ HistoryRecord r;
+ ProcessRecord anrApp = null;
synchronized(service) {
- HistoryRecord r = getWaitingHistoryRecordLocked();
+ r = getWaitingHistoryRecordLocked();
if (r != null && r.app != null) {
if (r.app.debugging) {
return false;
@@ -472,8 +474,7 @@
}
if (r.app.instrumentationClass == null) {
- service.appNotRespondingLocked(r.app, r, this,
- "keyDispatchingTimedOut");
+ anrApp = r.app;
} else {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
@@ -482,8 +483,14 @@
r.app, Activity.RESULT_CANCELED, info);
}
}
- return true;
}
+
+ if (anrApp != null) {
+ service.appNotResponding(anrApp, r, this,
+ "keyDispatchingTimedOut");
+ }
+
+ return true;
}
/** Returns the key dispatching timeout for this application token. */