summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java29
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessListener.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java4
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) {
}