From 7bb2581e6f404da0edba9ebb81b0d0593715eb40 Mon Sep 17 00:00:00 2001 From: Magnus Edlund Date: Wed, 24 Feb 2010 15:45:06 +0100 Subject: Fix problem with restarting an application process that recently has died. There exists a race condition when starting a process that recently has died. If the ActivityManager receives the death notification for the died process after the new process has been started but before an application thread has been attached to the new process will the newly created process be removed during the cleanup of the died process. If this happens when sending a broadcast could it result in an ANR. This is solved by doing the clean up before starting a new process that uses the same process record. --- .../android/server/am/ActivityManagerService.java | 24 +++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 1a22a26a5317..5f6356d97edb 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1905,11 +1905,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen + " app=" + app + " knownToBeDead=" + knownToBeDead + " thread=" + (app != null ? app.thread : null) + " pid=" + (app != null ? app.pid : -1)); - if (app != null && - (!knownToBeDead || app.thread == null) && app.pid > 0) { - return app; + if (app != null && app.pid > 0) { + if (!knownToBeDead || app.thread == null) { + return app; + } else { + // An application record is attached to a previous process, + // clean it up now. + handleAppDiedLocked(app, true); + } } - + String hostingNameStr = hostingName != null ? hostingName.flattenToShortString() : null; @@ -4553,7 +4558,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mProcDeaths[0]++; - if (app.thread != null && app.thread.asBinder() == thread.asBinder()) { + // Clean up already done if the process has been re-started. + if (app.pid == pid && app.thread != null && + app.thread.asBinder() == thread.asBinder()) { Log.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died."); EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName); @@ -4603,6 +4610,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen scheduleAppGcsLocked(); } } + } else if (app.pid != pid) { + // A new process has already been started. + Log.i(TAG, "Process " + app.processName + " (pid " + pid + + ") has died and restarted (pid " + app.pid + ")."); + EventLog.writeEvent(LOG_AM_PROCESS_DIED, pid, app.processName); } else if (Config.LOGD) { Log.d(TAG, "Received spurious death notification for thread " + thread.asBinder()); @@ -5424,6 +5436,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen finishReceiverLocked(br.receiver, br.resultCode, br.resultData, br.resultExtras, br.resultAbort, true); scheduleBroadcastsLocked(); + // We need to reset the state if we fails to start the receiver. + br.state = BroadcastRecord.IDLE; } } -- cgit v1.2.3-59-g8ed1b