Loading services/core/java/com/android/server/am/ActivityManagerService.java +53 −16 Original line number Diff line number Diff line Loading @@ -6876,6 +6876,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } ProcessRecord dyingProc = null; if (cpr != null && cpr.proc != null) { providerRunning = !cpr.proc.killed; Loading @@ -6885,14 +6886,9 @@ public class ActivityManagerService extends IActivityManager.Stub // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see // how to test this case.) if (cpr.proc.killed && cpr.proc.killedByAm) { final long iden = Binder.clearCallingIdentity(); try { mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false, cpr.uid == cpr.proc.uid || cpr.proc.isolated, "getContentProviderImpl: %s (killedByAm)", startTime); } finally { Binder.restoreCallingIdentity(iden); } Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead"); // Now we are going to wait for the death before starting the new process. dyingProc = cpr.proc; } } Loading Loading @@ -6993,18 +6989,18 @@ public class ActivityManagerService extends IActivityManager.Stub // has been killed on us. We need to wait for a new // process to be started, and make sure its death // doesn't kill our process. Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false, true, "getContentProviderImpl: %s", startTime); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. // the provider... we will be killed during cleaning up, bail. return null; } // We'll just start a new process to host the content provider providerRunning = false; conn = null; dyingProc = cpr.proc; } else { cpr.proc.verifiedAdj = cpr.proc.setAdj; } Loading Loading @@ -7080,7 +7076,7 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "getContentProviderImpl: before getProviderByClass"); cpr = mProviderMap.getProviderByClass(comp, userId); checkTime(startTime, "getContentProviderImpl: after getProviderByClass"); final boolean firstClass = cpr == null; boolean firstClass = cpr == null; if (firstClass) { final long ident = Binder.clearCallingIdentity(); Loading Loading @@ -7111,6 +7107,13 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(ident); } } else if (dyingProc == cpr.proc) { // The old stable connection's client should be killed during proc cleaning up, // so do not re-use the old ContentProviderRecord, otherwise the new clients // could get killed unexpectedly. cpr = new ContentProviderRecord(cpr); // This is sort of "firstClass" firstClass = true; } checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord"); Loading Loading @@ -14270,10 +14273,19 @@ public class ActivityManagerService extends IActivityManager.Stub cpr.launchingApp = null; cpr.notifyAll(); } mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid)); final int userId = UserHandle.getUserId(cpr.uid); // Don't remove from provider map if it doesn't match // could be a new content provider is starting if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) { mProviderMap.removeProviderByClass(cpr.name, userId); } String names[] = cpr.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid)); // Don't remove from provider map if it doesn't match // could be a new content provider is starting if (mProviderMap.getProviderByName(names[j], userId) == cpr) { mProviderMap.removeProviderByName(names[j], userId); } } } Loading Loading @@ -14368,6 +14380,10 @@ public class ActivityManagerService extends IActivityManager.Stub // Remove published content providers. for (int i = app.pubProviders.size() - 1; i >= 0; i--) { ContentProviderRecord cpr = app.pubProviders.valueAt(i); if (cpr.proc != app) { // If the hosting process record isn't really us, bail out continue; } final boolean alwaysRemove = app.bad || !allowRestart; final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove); if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) { Loading Loading @@ -14453,6 +14469,27 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid, null).sendToTarget(); // If this is a precede instance of another process instance allowRestart = true; synchronized (app) { if (app.mSuccessor != null) { // We don't allow restart with this ProcessRecord now, // because we have created a new one already. allowRestart = false; // If it's persistent, add the successor to mPersistentStartingProcesses if (app.isPersistent() && !app.removed) { if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) { mPersistentStartingProcesses.add(app.mSuccessor); } } // clean up the field so the successor's proc starter could proceed. app.mSuccessor.mPrecedence = null; app.mSuccessor = null; // Notify if anyone is waiting for it. app.notifyAll(); } } // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. if (restarting) { Loading Loading @@ -14482,7 +14519,7 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController()); mProcessList.noteProcessDiedLocked(app); if (restart && !app.isolated) { if (restart && allowRestart && !app.isolated) { // We have components that still need to be running in the // process, so re-launch it. if (index < 0) { services/core/java/com/android/server/am/ProcessList.java +77 −61 Original line number Diff line number Diff line Loading @@ -1842,26 +1842,9 @@ public final class ProcessList { if (mService.mConstants.FLAG_PROCESS_START_ASYNC) { if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES, "Posting procStart msg for " + app.toShortString()); mService.mProcStartHandler.post(() -> { try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (mService) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } } }); mService.mProcStartHandler.post(() -> handleProcessStart( app, entryPoint, gids, runtimeFlags, mountExternal, requiredAbi, instructionSet, invokeWith, startSeq)); return true; } else { try { Loading @@ -1882,6 +1865,66 @@ public final class ProcessList { } } /** * Main handler routine to start the given process from the ProcStartHandler. * * <p>Note: this function doesn't hold the global AM lock intentionally.</p> */ private void handleProcessStart(final ProcessRecord app, final String entryPoint, final int[] gids, final int runtimeFlags, final int mountExternal, final String requiredAbi, final String instructionSet, final String invokeWith, final long startSeq) { // If there is a precede instance of the process, wait for its death with a timeout. // Use local reference since we are not using locks here final ProcessRecord precedence = app.mPrecedence; if (precedence != null) { final int pid = precedence.pid; long now = System.currentTimeMillis(); final long end = now + PROC_KILL_TIMEOUT; try { Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT); // It's killed successfully, but we'd make sure the cleanup work is done. synchronized (precedence) { if (app.mPrecedence != null) { now = System.currentTimeMillis(); if (now < end) { try { precedence.wait(end - now); } catch (InterruptedException e) { } } } if (app.mPrecedence != null) { // The cleanup work hasn't be done yet, let's log it and continue. Slog.w(TAG, precedence + " has died, but its cleanup isn't done"); } } } catch (Exception e) { // It's still alive... Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch " + app); } } try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (mService) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } } } @GuardedBy("mService") public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) { final ApplicationInfo appInfo = appZygote.getAppInfo(); Loading Loading @@ -2136,6 +2179,7 @@ public final class ProcessList { + " app=" + app + " knownToBeDead=" + knownToBeDead + " thread=" + (app != null ? app.thread : null) + " pid=" + (app != null ? app.pid : -1)); ProcessRecord precedence = null; if (app != null && app.pid > 0) { if ((!knownToBeDead && !app.killed) || app.thread == null) { // We already have the app running, or are waiting for it to Loading @@ -2150,9 +2194,15 @@ public final class ProcessList { // An application record is attached to a previous process, // clean it up now. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app); // do the killing killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated, "startProcess: bad proc running, killing: %s", startTime); checkSlow(startTime, "startProcess: bad proc running, killing"); ProcessList.killProcessGroup(app.uid, app.pid); checkSlow(startTime, "startProcess: done killing old proc"); Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process"); // We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup // routine of it yet, but we'd set it as the precedence of the new process. precedence = app; app = null; } if (app == null) { Loading @@ -2166,6 +2216,10 @@ public final class ProcessList { app.crashHandler = crashHandler; app.isolatedEntryPoint = entryPoint; app.isolatedEntryPointArgs = entryPointArgs; if (precedence != null) { app.mPrecedence = precedence; precedence.mSuccessor = app; } checkSlow(startTime, "startProcess: done creating new process record"); } else { // If this is a new package in the process, add the package to the list Loading Loading @@ -2193,44 +2247,6 @@ public final class ProcessList { return success ? app : null; } /** * Kill (if asked to) and wait for the given process died if necessary * @param app - The process record to kill * @param doKill - Kill the given process record * @param wait - Wait for the death of the given process * @param formatString - The log message for slow operation * @param startTime - The start timestamp of the operation */ @GuardedBy("mService") void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill, final boolean wait, final String formatString, final long startTime) { checkSlow(startTime, String.format(formatString, "before appDied")); if (doKill) { // do the killing ProcessList.killProcessGroup(app.uid, app.pid); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_UNKNOWN, String.format(formatString, "")); } // wait for the death if (wait) { try { Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT); } catch (Exception e) { // Maybe the process goes into zombie, use an expensive API to check again. if (mService.isProcessAliveLocked(app)) { Slog.w(TAG, String.format(formatString, "waiting for app killing timed out")); } } } checkSlow(startTime, String.format(formatString, "after appDied")); } @GuardedBy("mService") private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) { StringBuilder sb = null; Loading services/core/java/com/android/server/am/ProcessRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -320,6 +320,14 @@ class ProcessRecord implements WindowProcessListener { // set of disabled compat changes for the process (all others are enabled) long[] mDisabledCompatChanges; // The precede instance of the process, which would exist when the previous process is killed // but not fully dead yet; in this case, the new instance of the process should be held until // this precede instance is fully dead. volatile ProcessRecord mPrecedence; // The succeeding instance of the process, which is going to be started after this process // is killed successfully. volatile ProcessRecord mSuccessor; // Cached task info for OomAdjuster private static final int VALUE_INVALID = -1; private static final int VALUE_FALSE = 0; Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +53 −16 Original line number Diff line number Diff line Loading @@ -6876,6 +6876,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } ProcessRecord dyingProc = null; if (cpr != null && cpr.proc != null) { providerRunning = !cpr.proc.killed; Loading @@ -6885,14 +6886,9 @@ public class ActivityManagerService extends IActivityManager.Stub // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see // how to test this case.) if (cpr.proc.killed && cpr.proc.killedByAm) { final long iden = Binder.clearCallingIdentity(); try { mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false, cpr.uid == cpr.proc.uid || cpr.proc.isolated, "getContentProviderImpl: %s (killedByAm)", startTime); } finally { Binder.restoreCallingIdentity(iden); } Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead"); // Now we are going to wait for the death before starting the new process. dyingProc = cpr.proc; } } Loading Loading @@ -6993,18 +6989,18 @@ public class ActivityManagerService extends IActivityManager.Stub // has been killed on us. We need to wait for a new // process to be started, and make sure its death // doesn't kill our process. Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false, true, "getContentProviderImpl: %s", startTime); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. // the provider... we will be killed during cleaning up, bail. return null; } // We'll just start a new process to host the content provider providerRunning = false; conn = null; dyingProc = cpr.proc; } else { cpr.proc.verifiedAdj = cpr.proc.setAdj; } Loading Loading @@ -7080,7 +7076,7 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "getContentProviderImpl: before getProviderByClass"); cpr = mProviderMap.getProviderByClass(comp, userId); checkTime(startTime, "getContentProviderImpl: after getProviderByClass"); final boolean firstClass = cpr == null; boolean firstClass = cpr == null; if (firstClass) { final long ident = Binder.clearCallingIdentity(); Loading Loading @@ -7111,6 +7107,13 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(ident); } } else if (dyingProc == cpr.proc) { // The old stable connection's client should be killed during proc cleaning up, // so do not re-use the old ContentProviderRecord, otherwise the new clients // could get killed unexpectedly. cpr = new ContentProviderRecord(cpr); // This is sort of "firstClass" firstClass = true; } checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord"); Loading Loading @@ -14270,10 +14273,19 @@ public class ActivityManagerService extends IActivityManager.Stub cpr.launchingApp = null; cpr.notifyAll(); } mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid)); final int userId = UserHandle.getUserId(cpr.uid); // Don't remove from provider map if it doesn't match // could be a new content provider is starting if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) { mProviderMap.removeProviderByClass(cpr.name, userId); } String names[] = cpr.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid)); // Don't remove from provider map if it doesn't match // could be a new content provider is starting if (mProviderMap.getProviderByName(names[j], userId) == cpr) { mProviderMap.removeProviderByName(names[j], userId); } } } Loading Loading @@ -14368,6 +14380,10 @@ public class ActivityManagerService extends IActivityManager.Stub // Remove published content providers. for (int i = app.pubProviders.size() - 1; i >= 0; i--) { ContentProviderRecord cpr = app.pubProviders.valueAt(i); if (cpr.proc != app) { // If the hosting process record isn't really us, bail out continue; } final boolean alwaysRemove = app.bad || !allowRestart; final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove); if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) { Loading Loading @@ -14453,6 +14469,27 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid, null).sendToTarget(); // If this is a precede instance of another process instance allowRestart = true; synchronized (app) { if (app.mSuccessor != null) { // We don't allow restart with this ProcessRecord now, // because we have created a new one already. allowRestart = false; // If it's persistent, add the successor to mPersistentStartingProcesses if (app.isPersistent() && !app.removed) { if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) { mPersistentStartingProcesses.add(app.mSuccessor); } } // clean up the field so the successor's proc starter could proceed. app.mSuccessor.mPrecedence = null; app.mSuccessor = null; // Notify if anyone is waiting for it. app.notifyAll(); } } // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. if (restarting) { Loading Loading @@ -14482,7 +14519,7 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController()); mProcessList.noteProcessDiedLocked(app); if (restart && !app.isolated) { if (restart && allowRestart && !app.isolated) { // We have components that still need to be running in the // process, so re-launch it. if (index < 0) {
services/core/java/com/android/server/am/ProcessList.java +77 −61 Original line number Diff line number Diff line Loading @@ -1842,26 +1842,9 @@ public final class ProcessList { if (mService.mConstants.FLAG_PROCESS_START_ASYNC) { if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES, "Posting procStart msg for " + app.toShortString()); mService.mProcStartHandler.post(() -> { try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (mService) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } } }); mService.mProcStartHandler.post(() -> handleProcessStart( app, entryPoint, gids, runtimeFlags, mountExternal, requiredAbi, instructionSet, invokeWith, startSeq)); return true; } else { try { Loading @@ -1882,6 +1865,66 @@ public final class ProcessList { } } /** * Main handler routine to start the given process from the ProcStartHandler. * * <p>Note: this function doesn't hold the global AM lock intentionally.</p> */ private void handleProcessStart(final ProcessRecord app, final String entryPoint, final int[] gids, final int runtimeFlags, final int mountExternal, final String requiredAbi, final String instructionSet, final String invokeWith, final long startSeq) { // If there is a precede instance of the process, wait for its death with a timeout. // Use local reference since we are not using locks here final ProcessRecord precedence = app.mPrecedence; if (precedence != null) { final int pid = precedence.pid; long now = System.currentTimeMillis(); final long end = now + PROC_KILL_TIMEOUT; try { Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT); // It's killed successfully, but we'd make sure the cleanup work is done. synchronized (precedence) { if (app.mPrecedence != null) { now = System.currentTimeMillis(); if (now < end) { try { precedence.wait(end - now); } catch (InterruptedException e) { } } } if (app.mPrecedence != null) { // The cleanup work hasn't be done yet, let's log it and continue. Slog.w(TAG, precedence + " has died, but its cleanup isn't done"); } } } catch (Exception e) { // It's still alive... Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch " + app); } } try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (mService) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } } } @GuardedBy("mService") public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) { final ApplicationInfo appInfo = appZygote.getAppInfo(); Loading Loading @@ -2136,6 +2179,7 @@ public final class ProcessList { + " app=" + app + " knownToBeDead=" + knownToBeDead + " thread=" + (app != null ? app.thread : null) + " pid=" + (app != null ? app.pid : -1)); ProcessRecord precedence = null; if (app != null && app.pid > 0) { if ((!knownToBeDead && !app.killed) || app.thread == null) { // We already have the app running, or are waiting for it to Loading @@ -2150,9 +2194,15 @@ public final class ProcessList { // An application record is attached to a previous process, // clean it up now. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app); // do the killing killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated, "startProcess: bad proc running, killing: %s", startTime); checkSlow(startTime, "startProcess: bad proc running, killing"); ProcessList.killProcessGroup(app.uid, app.pid); checkSlow(startTime, "startProcess: done killing old proc"); Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process"); // We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup // routine of it yet, but we'd set it as the precedence of the new process. precedence = app; app = null; } if (app == null) { Loading @@ -2166,6 +2216,10 @@ public final class ProcessList { app.crashHandler = crashHandler; app.isolatedEntryPoint = entryPoint; app.isolatedEntryPointArgs = entryPointArgs; if (precedence != null) { app.mPrecedence = precedence; precedence.mSuccessor = app; } checkSlow(startTime, "startProcess: done creating new process record"); } else { // If this is a new package in the process, add the package to the list Loading Loading @@ -2193,44 +2247,6 @@ public final class ProcessList { return success ? app : null; } /** * Kill (if asked to) and wait for the given process died if necessary * @param app - The process record to kill * @param doKill - Kill the given process record * @param wait - Wait for the death of the given process * @param formatString - The log message for slow operation * @param startTime - The start timestamp of the operation */ @GuardedBy("mService") void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill, final boolean wait, final String formatString, final long startTime) { checkSlow(startTime, String.format(formatString, "before appDied")); if (doKill) { // do the killing ProcessList.killProcessGroup(app.uid, app.pid); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_UNKNOWN, String.format(formatString, "")); } // wait for the death if (wait) { try { Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT); } catch (Exception e) { // Maybe the process goes into zombie, use an expensive API to check again. if (mService.isProcessAliveLocked(app)) { Slog.w(TAG, String.format(formatString, "waiting for app killing timed out")); } } } checkSlow(startTime, String.format(formatString, "after appDied")); } @GuardedBy("mService") private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) { StringBuilder sb = null; Loading
services/core/java/com/android/server/am/ProcessRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -320,6 +320,14 @@ class ProcessRecord implements WindowProcessListener { // set of disabled compat changes for the process (all others are enabled) long[] mDisabledCompatChanges; // The precede instance of the process, which would exist when the previous process is killed // but not fully dead yet; in this case, the new instance of the process should be held until // this precede instance is fully dead. volatile ProcessRecord mPrecedence; // The succeeding instance of the process, which is going to be started after this process // is killed successfully. volatile ProcessRecord mSuccessor; // Cached task info for OomAdjuster private static final int VALUE_INVALID = -1; private static final int VALUE_FALSE = 0; Loading