More app ops fg/bg tuning

- Only report that something has changed when a uid changes between
  the restricted and unrestricted states.  (Adds new constant that
  defines this important division point.)

- Have different settle times for different key transitions: (a)
  out of the top state, (b) out of any other unrestricted state,
  (c) down to a lower background state.

- But, don't apply any settle time when transitioning from top to
  another unrestricted state...  there is no need to.

Bug: 78480444
Test: manual
Change-Id: Ife772858009a6da5c286e285a4059aea3ad3f6c7
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 4c914c2..61b1dcc 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -95,11 +95,12 @@
 import java.util.List;
 import java.util.Map;
 
+import static android.app.AppOpsManager._NUM_UID_STATE;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
-import static android.app.AppOpsManager._NUM_UID_STATE;
+import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
 import static android.app.AppOpsManager.UID_STATE_TOP;
 
@@ -213,15 +214,31 @@
      */
     private final class Constants extends ContentObserver {
         // Key names stored in the settings value.
-        private static final String KEY_STATE_SETTLE_TIME = "state_settle_time";
+        private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
+        private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
+                = "fg_service_state_settle_time";
+        private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
 
         /**
-         * How long we want for a drop in uid state to settle before applying it.
+         * How long we want for a drop in uid state from top to settle before applying it.
          * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see #KEY_STATE_SETTLE_TIME
+         * @see #KEY_TOP_STATE_SETTLE_TIME
          */
-        public long STATE_SETTLE_TIME;
+        public long TOP_STATE_SETTLE_TIME;
 
+        /**
+         * How long we want for a drop in uid state from foreground to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
+         */
+        public long FG_SERVICE_STATE_SETTLE_TIME;
+
+        /**
+         * How long we want for a drop in uid state from background to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_BG_STATE_SETTLE_TIME
+         */
+        public long BG_STATE_SETTLE_TIME;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
         private ContentResolver mResolver;
@@ -256,16 +273,24 @@
                     // with defaults.
                     Slog.e(TAG, "Bad app ops settings", e);
                 }
-                STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_STATE_SETTLE_TIME, 10 * 1000L);
+                TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
+                FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
+                BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
             }
         }
 
         void dump(PrintWriter pw) {
             pw.println("  Settings:");
 
-            pw.print("    "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
+            pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
+            pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
+            pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
             pw.println();
         }
     }
@@ -304,7 +329,7 @@
 
         int evalMode(int mode) {
             if (mode == AppOpsManager.MODE_FOREGROUND) {
-                return state <= UID_STATE_FOREGROUND_SERVICE
+                return state <= UID_STATE_LAST_NON_RESTRICTED
                         ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
             }
             return mode;
@@ -728,14 +753,22 @@
             if (uidState != null && uidState.pendingState != newState) {
                 final int oldPendingState = uidState.pendingState;
                 uidState.pendingState = newState;
-                if (newState < uidState.state) {
-                    // We are moving to a more important state, always do it immediately.
+                if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
+                    // We are moving to a more important state, or the new state is in the
+                    // foreground, then always do it immediately.
                     commitUidPendingStateLocked(uidState);
                 } else if (uidState.pendingStateCommitTime == 0) {
                     // We are moving to a less important state for the first time,
                     // delay the application for a bit.
-                    uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
-                            mConstants.STATE_SETTLE_TIME;
+                    final long settleTime;
+                    if (uidState.state <= UID_STATE_TOP) {
+                        settleTime = mConstants.TOP_STATE_SETTLE_TIME;
+                    } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
+                        settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
+                    } else {
+                        settleTime = mConstants.BG_STATE_SETTLE_TIME;
+                    }
+                    uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + settleTime;
                 }
                 if (uidState.startNesting != 0) {
                     // There is some actively running operation...  need to find it
@@ -1858,9 +1891,11 @@
     }
 
     private void commitUidPendingStateLocked(UidState uidState) {
+        final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
+        final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
         uidState.state = uidState.pendingState;
         uidState.pendingStateCommitTime = 0;
-        if (uidState.hasForegroundWatchers) {
+        if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
             for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
                 if (!uidState.foregroundOps.valueAt(fgi)) {
                     continue;