Top apps may start fg services even when under bg restriction

We now apply bg restriction policy (appop) on being able to enter a
foreground service lifecycle only when the app is not in a "top" i.e.
directly user-facing state.  This avoids breaking existing supported
lifecycle guarantees involving the order of calls to startService(),
startForeground(), and startForegroundService().  Briefly:  there is a
designed behavior in the following sequence:

  1. startService(intent);
  2. startForeground() on that service; then
  3. startForegroundService(intent)

The intentional behavior is that after step 3, the app is not required
to call startForeground() *again,* redundantly; because that service is
already in a fg lifecycle.

However, new-in-Q code broke this pattern in the case where the user had
imposed bg service restrictions on the app.  For this and for
semantic/model reasons, we now do not apply fg service start
restrictions to the user-facing app, even if the at app is under bg
execution restrictions.  The app is not background at that time, so
should not be expected to face a different execution environment.

Bug: 130048629
Test: Foreground use of GPM under bg restrictions
Change-Id: I0e8c308ac26211082a90c165a64d66b31ab804df
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 24f8fc2..76136df 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -828,6 +828,13 @@
                         sb.append(compName);
                         Slog.w(TAG, sb.toString());
                         stopping.add(service);
+
+                        // If the app is under bg restrictions, also make sure that
+                        // any notification is dismissed
+                        if (appRestrictedAnyInBackground(
+                                service.appInfo.uid, service.packageName)) {
+                            cancelForegroundNotificationLocked(service);
+                        }
                     }
                 }
             }
@@ -1232,6 +1239,10 @@
         }
     }
 
+    private boolean appIsTopLocked(int uid) {
+        return mAm.getUidState(uid) <= ActivityManager.PROCESS_STATE_TOP;
+    }
+
     /**
      * @param id Notification ID.  Zero === exit foreground state for the given service.
      */
@@ -1318,8 +1329,11 @@
                         throw new SecurityException("Foreground not allowed as per app op");
                 }
 
-                if (!ignoreForeground &&
-                        appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
+                // Apps that are TOP or effectively similar may call startForeground() on
+                // their services even if they are restricted from doing that while in bg.
+                if (!ignoreForeground
+                        && !appIsTopLocked(r.appInfo.uid)
+                        && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
                     Slog.w(TAG,
                             "Service.startForeground() not allowed due to bg restriction: service "
                             + r.shortInstanceName);