Merge "Creates new FLAG_APP_INACCESSIBLE flag for DeviceState" into tm-dev
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index e37d7b0..6076eb1 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -1115,6 +1115,14 @@
                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_on_long_running";
 
         /**
+         * The behavior for an app with a FGS, when the system detects it's running for
+         * a very long time, should we prompt the user.
+         * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
+         */
+        static final String KEY_BG_PROMPT_FGS_ON_LONG_RUNNING =
+                DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_on_long_running";
+
+        /**
          * The list of packages to be exempted from all these background restrictions.
          */
         static final String KEY_BG_RESTRICTION_EXEMPTED_PACKAGES =
@@ -1154,6 +1162,11 @@
         static final boolean DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING = false;
 
         /**
+         * Default value to {@link #mBgPromptFgsOnLongRunning}.
+         */
+        static final boolean DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING = true;
+
+        /**
          * Default value to {@link #mBgPromptFgsWithNotiToBgRestricted}.
          */
         final boolean mDefaultBgPromptFgsWithNotiToBgRestricted;
@@ -1191,6 +1204,11 @@
         volatile boolean mBgPromptFgsWithNotiOnLongRunning;
 
         /**
+         * @see #KEY_BG_PROMPT_FGS_ON_LONG_RUNNING.
+         */
+        volatile boolean mBgPromptFgsOnLongRunning;
+
+        /**
          * @see #KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED.
          */
         volatile boolean mBgPromptAbusiveAppsToBgRestricted;
@@ -1228,6 +1246,9 @@
                     case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING:
                         updateBgPromptFgsWithNotiOnLongRunning();
                         break;
+                    case KEY_BG_PROMPT_FGS_ON_LONG_RUNNING:
+                        updateBgPromptFgsOnLongRunning();
+                        break;
                     case KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED:
                         updateBgPromptAbusiveAppToBgRestricted();
                         break;
@@ -1269,6 +1290,7 @@
             updateBgLongFgsNotificationMinimalInterval();
             updateBgPromptFgsWithNotiToBgRestricted();
             updateBgPromptFgsWithNotiOnLongRunning();
+            updateBgPromptFgsOnLongRunning();
             updateBgPromptAbusiveAppToBgRestricted();
             updateBgRestrictionExemptedPackages();
         }
@@ -1319,6 +1341,13 @@
                     DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
         }
 
+        private void updateBgPromptFgsOnLongRunning() {
+            mBgPromptFgsOnLongRunning = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
+                    DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
+        }
+
         private void updateBgPromptAbusiveAppToBgRestricted() {
             mBgPromptAbusiveAppsToBgRestricted = DeviceConfig.getBoolean(
                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1365,6 +1394,14 @@
             pw.print('=');
             pw.println(mBgLongFgsNotificationMinIntervalMs);
             pw.print(prefix);
+            pw.print(KEY_BG_PROMPT_FGS_ON_LONG_RUNNING);
+            pw.print('=');
+            pw.println(mBgPromptFgsOnLongRunning);
+            pw.print(prefix);
+            pw.print(KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
+            pw.print('=');
+            pw.println(mBgPromptFgsWithNotiOnLongRunning);
+            pw.print(prefix);
             pw.print(KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED);
             pw.print('=');
             pw.println(mBgPromptFgsWithNotiToBgRestricted);
@@ -2500,6 +2537,12 @@
                     ActivityManager.isLowRamDeviceStatic(),
                     mBgController.getRestrictionLevel(uid));
             PendingIntent pendingIntent;
+            if (!mBgController.mConstantsObserver.mBgPromptFgsOnLongRunning) {
+                if (DEBUG_BG_RESTRICTION_CONTROLLER) {
+                    Slog.i(TAG, "Long-running FGS prompt is disabled.");
+                }
+                return;
+            }
             if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiOnLongRunning
                     && mBgController.hasForegroundServiceNotifications(packageName, uid)) {
                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index 9fddc76..181c39e 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -418,7 +418,9 @@
         } else if (changed) {
             invalidateCache("grantImplicitAccess: " + recipientUid + " -> " + visibleUid);
         }
-        onChanged();
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4f8c792..94e8ec5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2859,12 +2859,15 @@
         mDexOptHelper.performPackageDexOptUpgradeIfNeeded();
     }
 
-
     private void notifyPackageUseInternal(String packageName, int reason) {
         long time = System.currentTimeMillis();
-        commitPackageStateMutation(null, packageName, packageState -> {
-            packageState.setLastPackageUsageTime(reason, time);
-        });
+        synchronized (mLock) {
+            final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+            if (pkgSetting == null) {
+                return;
+            }
+            pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, time);
+        }
     }
 
     /*package*/ DexManager getDexManager() {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index 7bd720a..5251fe0 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -79,7 +79,10 @@
             return this;
         }
         getLastPackageUsageTimeInMills()[reason] = time;
-        mPackageSetting.onChanged();
+        // TODO(b/236180425): This method does not notify snapshot changes because it's called too
+        //  frequently, causing too many re-takes. This should be moved to a separate data structure
+        //  or merged with the general UsageStats to avoid tracking heavily mutated data in the
+        //  package data snapshot.
         return this;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index fa8d569..f02571f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -1141,6 +1141,7 @@
         DeviceConfigSession<Long> longRunningFGSWindow = null;
         DeviceConfigSession<Long> longRunningFGSThreshold = null;
         DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
+        DeviceConfigSession<Boolean> longRunningFGS = null;
 
         try {
             longRunningFGSMonitor = new DeviceConfigSession<>(
@@ -1171,6 +1172,13 @@
                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
             longRunningFGSWithNotification.set(true);
 
+            longRunningFGS = new DeviceConfigSession<>(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    ConstantsObserver.KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
+                    DeviceConfig::getBoolean,
+                    ConstantsObserver.DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
+            longRunningFGS.set(true);
+
             // Basic case
             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName1, testUid1,
                     testPid1, true);
@@ -1214,6 +1222,23 @@
                     testPid2, false);
             checkNotificationGone(testPkgName2, timeout(windowMs), notificationId);
 
+            // Turn OFF the notification.
+            longRunningFGS.set(false);
+            clearInvocations(mInjector.getNotificationManager());
+            mBgRestrictionController.resetRestrictionSettings();
+            // Start the FGS again.
+            mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
+                    testPid2, true);
+            // Verify we do NOT have the notification.
+            checkNotificationShown(
+                    new String[] {testPkgName2}, timeout(windowMs * 2).times(0), false);
+            // Stop this FGS
+            mAppFGSTracker.onForegroundServiceStateChanged(testPkgName2, testUid2,
+                    testPid2, false);
+
+            // Turn it back ON.
+            longRunningFGS.set(true);
+
             // Start over with concurrent cases.
             clearInvocations(mInjector.getNotificationManager());
             mBgRestrictionController.resetRestrictionSettings();
@@ -1306,6 +1331,7 @@
             closeIfNotNull(longRunningFGSWindow);
             closeIfNotNull(longRunningFGSThreshold);
             closeIfNotNull(longRunningFGSWithNotification);
+            closeIfNotNull(longRunningFGS);
         }
     }
 
@@ -1332,6 +1358,7 @@
         DeviceConfigSession<Long> mediaPlaybackFGSThreshold = null;
         DeviceConfigSession<Long> locationFGSThreshold = null;
         DeviceConfigSession<Boolean> longRunningFGSWithNotification = null;
+        DeviceConfigSession<Boolean> longRunningFGS = null;
 
         doReturn(testPkgName1).when(mInjector).getPackageName(testPid1);
         doReturn(testPkgName2).when(mInjector).getPackageName(testPid2);
@@ -1379,6 +1406,13 @@
                     ConstantsObserver.DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
             longRunningFGSWithNotification.set(true);
 
+            longRunningFGS = new DeviceConfigSession<>(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    ConstantsObserver.KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
+                    DeviceConfig::getBoolean,
+                    ConstantsObserver.DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
+            longRunningFGS.set(true);
+
             // Long-running FGS with type "location", but ran for a very short time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, OP_NONE, null, null,
@@ -1487,6 +1521,7 @@
             closeIfNotNull(mediaPlaybackFGSThreshold);
             closeIfNotNull(locationFGSThreshold);
             closeIfNotNull(longRunningFGSWithNotification);
+            closeIfNotNull(longRunningFGS);
         }
     }