Full teardown when the user stops background apps
Not just moving its services out of the FGS mode.
The shell command for invoking this operation has changed; it is now
adb shell cmd activity stop-app [--user NUM] PACKAGE
Bug: 192504071
Test: manual (Maps nav, YouTube, etc)
Test: atest CtsAppTestCases:android.app.cts.ServiceTest
Test: atest RunningFgsControllerTest
Change-Id: Ic14c1ba557460e25dd1ba2fd79462918e9a47377
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 96487de..74a5526 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -528,9 +528,11 @@
Notification notification, int id, String pkg, @UserIdInt int userId);
/**
- * Un-foreground all foreground services in the given app.
+ * Fully stop the given app's processes without restoring service starts or
+ * bindings, but without the other durable effects of the full-scale
+ * "force stop" intervention.
*/
- public abstract void makeServicesNonForeground(String pkg, @UserIdInt int userId);
+ public abstract void stopAppForUser(String pkg, @UserIdInt int userId);
/**
* If the given app has any FGSs whose notifications are in the given channel,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index a2578d6..bdcec42 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -279,7 +279,7 @@
List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
boolean clearApplicationUserData(in String packageName, boolean keepState,
in IPackageDataObserver observer, int userId);
- void makeServicesNonForeground(in String packageName, int userId);
+ void stopAppForUser(in String packageName, int userId);
/** Returns {@code false} if the callback could not be registered, {@true} otherwise. */
boolean registerForegroundServiceObserver(in IForegroundServiceObserver callback);
@UnsupportedAppUsage
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
index d44d365..6d3345d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
@@ -108,7 +108,7 @@
override fun stopFgs(userId: Int, packageName: String) {
init()
try {
- activityManager.makeServicesNonForeground(packageName, userId)
+ activityManager.stopAppForUser(packageName, userId)
} catch (e: RemoteException) {
e.rethrowFromSystemServer()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
index c7c8d04..6059afe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
@@ -246,7 +246,7 @@
public void testStopFgs() throws RemoteException {
String pkgName = "package.name";
mController.stopFgs(0, pkgName);
- verify(mActivityManager).makeServicesNonForeground(pkgName, 0);
+ verify(mActivityManager).stopAppForUser(pkgName, 0);
}
/**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8887108..e14dce8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5138,29 +5138,6 @@
return didSomething;
}
- void makeServicesNonForegroundLocked(final String pkg, final @UserIdInt int userId) {
- final ServiceMap smap = mServiceMap.get(userId);
- if (smap != null) {
- ArrayList<ServiceRecord> fgsList = new ArrayList<>();
- for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
- final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
- if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
- fgsList.add(sr);
- }
- }
-
- final int numServices = fgsList.size();
- if (DEBUG_FOREGROUND_SERVICE) {
- Slog.i(TAG_SERVICE, "Forcing " + numServices + " services out of foreground in u"
- + userId + "/" + pkg);
- }
- for (int i = 0; i < numServices; i++) {
- final ServiceRecord sr = fgsList.get(i);
- setServiceForegroundInnerLocked(sr, 0, null, Service.STOP_FOREGROUND_REMOVE, 0);
- }
- }
- }
-
@GuardedBy("mAm")
private void signalForegroundServiceObserversLocked(ServiceRecord r) {
final int num = mFgsObservers.beginBroadcast();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b1b4c44..eec6e27 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3820,10 +3820,10 @@
}
@Override
- public void makeServicesNonForeground(final String packageName, int userId) {
+ public void stopAppForUser(final String packageName, int userId) {
if (checkCallingPermission(MANAGE_ACTIVITY_TASKS)
!= PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: makeServicesNonForeground() from pid="
+ String msg = "Permission Denial: stopAppForUser() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + MANAGE_ACTIVITY_TASKS;
@@ -3833,10 +3833,10 @@
final int callingPid = Binder.getCallingPid();
userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
- userId, true, ALLOW_FULL_ONLY, "makeServicesNonForeground", null);
+ userId, true, ALLOW_FULL_ONLY, "stopAppForUser", null);
final long callingId = Binder.clearCallingIdentity();
try {
- makeServicesNonForegroundUnchecked(packageName, userId);
+ stopAppForUserInternal(packageName, userId);
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -4171,13 +4171,6 @@
}
}
- private void makeServicesNonForegroundUnchecked(final String packageName,
- final @UserIdInt int userId) {
- synchronized (this) {
- mServices.makeServicesNonForegroundLocked(packageName, userId);
- }
- }
-
@GuardedBy("this")
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
@@ -4304,6 +4297,41 @@
mProcessList.killAppZygotesLocked(packageName, appId, userId, true /* force */);
}
+ void stopAppForUserInternal(final String packageName, @UserIdInt final int userId) {
+ final int uid = getPackageManagerInternal().getPackageUid(packageName,
+ MATCH_DEBUG_TRIAGED_MISSING | MATCH_ANY_USER, userId);
+ if (uid < 0) {
+ Slog.w(TAG, "Asked to stop " + packageName + "/u" + userId
+ + " but does not exist in that user");
+ return;
+ }
+ Slog.i(TAG, "Stopping app for user: " + packageName + "/" + userId);
+
+ // A specific subset of the work done in forceStopPackageLocked(), because we are
+ // intentionally not rendering the app nonfunctional; we're just halting its current
+ // execution.
+ final int appId = UserHandle.getAppId(uid);
+ synchronized (this) {
+ synchronized (mProcLock) {
+ mAtmInternal.onForceStopPackage(packageName, true, false, userId);
+
+ mProcessList.killPackageProcessesLSP(packageName, appId, userId,
+ ProcessList.INVALID_ADJ, true, false, true,
+ false, true /* setRemoved */, false,
+ ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "fully stop " + packageName + "/" + userId + " by user request");
+ }
+
+ mServices.bringDownDisabledPackageServicesLocked(
+ packageName, null, userId, false, true);
+
+ if (mBooted) {
+ mAtmInternal.resumeTopActivities(true);
+ }
+ }
+ }
+
@GuardedBy("this")
final boolean forceStopPackageLocked(String packageName, int appId,
boolean callerWillRestart, boolean purgeCache, boolean doit,
@@ -16591,8 +16619,8 @@
}
@Override
- public void makeServicesNonForeground(String pkg, int userId) {
- ActivityManagerService.this.makeServicesNonForegroundUnchecked(pkg, userId);
+ public void stopAppForUser(String pkg, @UserIdInt int userId) {
+ ActivityManagerService.this.stopAppForUserInternal(pkg, userId);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b6a0ec4..4705b7b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -240,8 +240,8 @@
return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
- case "stop-fgs":
- return runStopForegroundServices(pw);
+ case "stop-app":
+ return runStopApp(pw);
case "fgs-notification-rate-limit":
return runFgsNotificationRateLimit(pw);
case "crash":
@@ -1128,7 +1128,7 @@
return 0;
}
- int runStopForegroundServices(PrintWriter pw) throws RemoteException {
+ int runStopApp(PrintWriter pw) throws RemoteException {
int userId = UserHandle.USER_SYSTEM;
String opt;
@@ -1140,7 +1140,7 @@
return -1;
}
}
- mInterface.makeServicesNonForeground(getNextArgRequired(), userId);
+ mInterface.stopAppForUser(getNextArgRequired(), userId);
return 0;
}