diff options
9 files changed, 107 insertions, 72 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 15d7efb5a74a..d95604e91ca3 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3318,8 +3318,7 @@ public final class ActiveServices { } private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses, - boolean evenPersistent, boolean doit, boolean killProcess, - ArrayMap<ComponentName, ServiceRecord> services) { + boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) { boolean didSomething = false; for (int i = services.size() - 1; i >= 0; i--) { ServiceRecord service = services.valueAt(i); @@ -3334,13 +3333,10 @@ public final class ActiveServices { } didSomething = true; Slog.i(TAG, " Force stopping service " + service); - if (service.app != null) { - service.app.removed = killProcess; - if (!service.app.isPersistent()) { - service.app.services.remove(service); - if (service.whitelistManager) { - updateWhitelistManagerLocked(service.app); - } + if (service.app != null && !service.app.isPersistent()) { + service.app.services.remove(service); + if (service.whitelistManager) { + updateWhitelistManagerLocked(service.app); } } service.setProcess(null); @@ -3355,7 +3351,7 @@ public final class ActiveServices { } boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses, - int userId, boolean evenPersistent, boolean killProcess, boolean doit) { + int userId, boolean evenPersistent, boolean doit) { boolean didSomething = false; if (mTmpCollectionResults != null) { @@ -3365,8 +3361,7 @@ public final class ActiveServices { if (userId == UserHandle.USER_ALL) { for (int i = mServiceMap.size() - 1; i >= 0; i--) { didSomething |= collectPackageServicesLocked(packageName, filterByClasses, - evenPersistent, doit, killProcess, - mServiceMap.valueAt(i).mServicesByInstanceName); + evenPersistent, doit, mServiceMap.valueAt(i).mServicesByInstanceName); if (!doit && didSomething) { return true; } @@ -3379,7 +3374,7 @@ public final class ActiveServices { if (smap != null) { ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByInstanceName; didSomething = collectPackageServicesLocked(packageName, filterByClasses, - evenPersistent, doit, killProcess, items); + evenPersistent, doit, items); } if (doit && filterByClasses == null) { forceStopPackageLocked(packageName, userId); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ffed2e08b583..bec738666cbb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3891,7 +3891,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (this) { mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId, - ProcessList.SERVICE_ADJ, false, true, true, false, "kill background"); + ProcessList.SERVICE_ADJ, "kill background"); } } } finally { @@ -4252,7 +4252,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private void cleanupDisabledPackageComponentsLocked( - String packageName, int userId, boolean killProcess, String[] changedClasses) { + String packageName, int userId, String[] changedClasses) { Set<String> disabledClasses = null; boolean packageDisabled = false; @@ -4315,7 +4315,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Clean-up disabled services. mServices.bringDownDisabledPackageServicesLocked( - packageName, disabledClasses, userId, false, killProcess, true); + packageName, disabledClasses, userId, false /* evenPersistent */, true /* doIt */); // Clean-up disabled providers. ArrayList<ContentProviderRecord> providers = new ArrayList<>(); @@ -4372,14 +4372,15 @@ public class ActivityManagerService extends IActivityManager.Stub } boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId, - ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent, + ProcessList.INVALID_ADJ, callerWillRestart, true /* allowRestart */, doit, + evenPersistent, true /* setRemoved */, packageName == null ? ("stop user " + userId) : ("stop " + packageName)); didSomething |= mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId); if (mServices.bringDownDisabledPackageServicesLocked( - packageName, null, userId, evenPersistent, true, doit)) { + packageName, null /* filterByClasses */, userId, evenPersistent, doit)) { if (!doit) { return true; } @@ -8336,9 +8337,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { final long identity = Binder.clearCallingIdentity(); try { - mProcessList.killPackageProcessesLocked(null, appId, userId, - ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true, - reason != null ? reason : "kill uid"); + mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId, + ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, + true /* callerWillRestart */, true /* doit */, true /* evenPersistent */, + false /* setRemoved */, reason != null ? reason : "kill uid"); } finally { Binder.restoreCallingIdentity(identity); } @@ -14573,10 +14575,9 @@ public class ActivityManagerService extends IActivityManager.Stub -1); mProcessList.killPackageProcessesLocked(ssp, UserHandle.getAppId(extraUid), - userId, ProcessList.INVALID_ADJ, - false, true, true, false, "change " + ssp); + userId, ProcessList.INVALID_ADJ, "change " + ssp); } - cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess, + cleanupDisabledPackageComponentsLocked(ssp, userId, intent.getStringArrayExtra( Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)); } @@ -17232,10 +17233,8 @@ public class ActivityManagerService extends IActivityManager.Stub // We don't kill persistent processes. continue; } - if (app.removed) { - procs.add(app); - } else if (app.userId == userHandle && app.hasForegroundActivities()) { - app.removed = true; + if (app.removed + || (app.userId == userHandle && app.hasForegroundActivities())) { procs.add(app); } } @@ -18080,8 +18079,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized(this) { mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), - userId, ProcessList.FOREGROUND_APP_ADJ, false, true, true, false, - "dep: " + packageName); + userId, ProcessList.FOREGROUND_APP_ADJ, "dep: " + packageName); } } finally { Binder.restoreCallingIdentity(callingId); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index c2e77633510c..4aa71f9fbbe1 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2043,25 +2043,25 @@ public final class ProcessList { // We don't kill persistent processes. continue; } - if (app.removed) { - procs.add(app); - } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { - app.removed = true; + if (app.removed || app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { procs.add(app); } } } + } - final int N = procs.size(); - for (int i = 0; i < N; i++) { - removeProcessLocked(procs.get(i), false, true, "kill all background"); - } + @GuardedBy("mService") + boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, + String reason) { + return killPackageProcessesLocked(packageName, appId, userId, minOomAdj, + false /* callerWillRestart */, true /* allowRestart */, true /* doit */, + false /* evenPersistent */, false /* setRemoved */, reason); } @GuardedBy("mService") final boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart, - boolean doit, boolean evenPersistent, String reason) { + boolean doit, boolean evenPersistent, boolean setRemoved, String reason) { ArrayList<ProcessRecord> procs = new ArrayList<>(); // Remove all processes this package may have touched: all with the @@ -2119,7 +2119,9 @@ public final class ProcessList { if (!doit) { return true; } - app.removed = true; + if (setRemoved) { + app.removed = true; + } procs.add(app); } } @@ -2353,11 +2355,8 @@ public final class ProcessList { final int NA = apps.size(); for (int ia = 0; ia < NA; ia++) { final ProcessRecord app = apps.valueAt(ia); - if (app.removed) { - procs.add(app); - } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk) - && (maxProcState < 0 || app.setProcState > maxProcState)) { - app.removed = true; + if (app.removed || ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk) + && (maxProcState < 0 || app.setProcState > maxProcState))) { procs.add(app); } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 7e524631fcfe..580d6882a82e 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -266,7 +266,9 @@ final class ProcessRecord implements WindowProcessListener { boolean forceCrashReport; // suppress normal auto-dismiss of crash dialog & report UI? private boolean mNotResponding; // does the app have a not responding dialog? Dialog anrDialog; // dialog being displayed due to app not resp. - boolean removed; // has app package been removed from device? + volatile boolean removed; // Whether this process should be killed and removed from process + // list. It is set when the package is force-stopped or the process + // has crashed too many times. private boolean mDebugging; // was app launched for debugging? boolean waitedForDebugger; // has process show wait for debugger dialog? Dialog waitDialog; // current wait for debugger dialog @@ -1236,10 +1238,8 @@ final class ProcessRecord implements WindowProcessListener { } @Override - public void setRemoved(boolean removed) { - synchronized (mService) { - this.removed = removed; - } + public boolean isRemoved() { + return removed; } /** diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index b23dcb33720f..723f20381016 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4668,6 +4668,14 @@ class ActivityStack extends ConfigurationContainer { removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app, "mFinishingActivities"); + final boolean isProcessRemoved = app.isRemoved(); + if (isProcessRemoved) { + // The package of the died process should be force-stopped, so make its activities as + // finishing to prevent the process from being started again if the next top (or being + // visible) activity also resides in the same process. + app.makeFinishingForProcessRemoved(); + } + boolean hasVisibleActivities = false; // Clean out the history list. @@ -4720,7 +4728,7 @@ class ActivityStack extends ConfigurationContainer { + " stateNotNeeded=" + r.stateNotNeeded + " finishing=" + r.finishing + " state=" + r.getState() + " callers=" + Debug.getCallers(5)); - if (!r.finishing) { + if (!r.finishing || isProcessRemoved) { Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, r.mUserId, System.identityHashCode(r), @@ -5125,12 +5133,6 @@ class ActivityStack extends ConfigurationContainer { } didSomething = true; Slog.i(TAG, " Force finishing activity " + r); - if (sameComponent) { - if (r.hasProcess()) { - r.app.setRemoved(true); - } - r.app = null; - } lastTask = r.getTaskRecord(); finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", true); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 07f26b4c70bb..030cc05a2f7a 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -416,6 +416,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mActivities.remove(r); } + void makeFinishingForProcessRemoved() { + for (int i = mActivities.size() - 1; i >= 0; --i) { + mActivities.get(i).makeFinishingLocked(); + } + } + public void clearActivities() { synchronized (mAtm.mGlobalLock) { mActivities.clear(); @@ -693,12 +699,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mAtm.mH.sendMessage(m); } - void setRemoved(boolean removed) { - if (mListener == null) return; - // Posting on handler so WM lock isn't held when we call into AM. - final Message m = PooledLambda.obtainMessage( - WindowProcessListener::setRemoved, mListener, removed); - mAtm.mH.sendMessage(m); + boolean isRemoved() { + return mListener == null ? false : mListener.isRemoved(); } void clearWaitingToKill() { diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index bce5e2dfeb44..d732e4e8f341 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -44,8 +44,11 @@ public interface WindowProcessListener { void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru, boolean activityChange, boolean updateOomAdj); - /** Set process package been removed from device. */ - void setRemoved(boolean removed); + /** + * Returns true if the process is removed and we should completely clean up the related records + * belonging to this process. + */ + boolean isRemoved(); /** Returns the total time (in milliseconds) spent executing in both user and system code. */ long getCpuTime(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 35c1edeace2d..986943aaf146 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -34,6 +34,7 @@ import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; @@ -51,6 +52,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; @@ -647,20 +649,50 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testFinishDisabledPackageActivities() { + public void testFinishDisabledPackageActivities_FinishAliveActivities() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); + firstActivity.setState(STOPPED, "testFinishDisabledPackageActivities"); + secondActivity.setState(RESUMED, "testFinishDisabledPackageActivities"); + mStack.mResumedActivity = secondActivity; - // Making the second activity a task overlay without an app means it will be removed from - // the task's activities as well once first activity is removed. - secondActivity.mTaskOverlay = true; - secondActivity.app = null; + // Note the activities have non-null ActivityRecord.app, so it won't remove directly. + mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName, + null /* filterByClasses */, true /* doit */, true /* evenPersistent */, + UserHandle.USER_ALL); + + // If the activity is disabled with {@link android.content.pm.PackageManager#DONT_KILL_APP} + // the activity should still follow the normal flow to finish and destroy. + assertThat(firstActivity.getState()).isEqualTo(DESTROYING); + assertThat(secondActivity.getState()).isEqualTo(PAUSING); + assertTrue(secondActivity.finishing); + } + + @Test + public void testFinishDisabledPackageActivities_RemoveNonAliveActivities() { + final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build(); + + // The overlay activity is not in the disabled package but it is in the same task. + final ActivityRecord overlayActivity = new ActivityBuilder(mService).setTask(mTask) + .setComponent(new ComponentName("package.overlay", ".OverlayActivity")).build(); + // If the task only remains overlay activity, the task should also be removed. + // See {@link ActivityStack#removeActivityFromHistoryLocked}. + overlayActivity.mTaskOverlay = true; + + // The activity without an app means it will be removed immediately. + // See {@link ActivityStack#destroyActivityLocked}. + activity.app = null; + overlayActivity.app = null; assertEquals(2, mTask.mActivities.size()); - mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName, null, - true /* doit */, true /* evenPersistent */, UserHandle.USER_ALL); + mStack.finishDisabledPackageActivitiesLocked(activity.packageName, + null /* filterByClasses */, true /* doit */, true /* evenPersistent */, + UserHandle.USER_ALL); + // Although the overlay activity is in another package, the non-overlay activities are + // removed from the task. Since the overlay activity should be removed as well, the task + // should be empty. assertThat(mTask.mActivities).isEmpty(); assertThat(mStack.getAllTasks()).isEmpty(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index ea8f33f0c630..3b399ffc708c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -474,6 +474,10 @@ class ActivityTestsBase { } @Override + void updateCpuStats() { + } + + @Override void updateBatteryStats(ActivityRecord component, boolean resumed) { } |