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;
     }