Merge "Disable ClockOptionsProvider so clocks don't appear in picker app" into qt-dev
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 82593b5..1fdb1f3 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -458,7 +458,7 @@
     }
 
     private String getFuncTypeAsString() {
-        if (isRecycled()) throw new IllegalStateException();
+        if (isRecycled()) return "<recycled>";
         if (isConstSupplier()) return "supplier";
         String name = LambdaType.toString(getFlags(MASK_EXPOSED_AS));
         if (name.endsWith("Consumer")) return "consumer";
@@ -466,7 +466,7 @@
         if (name.endsWith("Predicate")) return "predicate";
         if (name.endsWith("Supplier")) return "supplier";
         if (name.endsWith("Runnable")) return "runnable";
-        throw new IllegalStateException("Don't know the string representation of " + name);
+        return name;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b342d37..33d6591 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -272,6 +272,7 @@
 import android.os.storage.StorageManager;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.provider.DeviceConfig.Properties;
 import android.server.ServerProtoEnums;
 import android.sysprop.VoldProperties;
 import android.text.TextUtils;
@@ -356,6 +357,7 @@
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.utils.PriorityDump;
 import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ActivityTaskManagerService;
@@ -392,6 +394,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiFunction;
 
@@ -861,6 +864,51 @@
      */
     final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
 
+    /**
+     * Depth of overlapping activity-start PSS deferral notes
+     */
+    private final AtomicInteger mActivityStartingNesting = new AtomicInteger(0);
+
+    private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
+            new ActivityMetricsLaunchObserver() {
+        @Override
+        public void onActivityLaunched(byte[] activity, int temperature) {
+            // This is safe to force to the head of the queue because it relies only
+            // on refcounting to track begin/end of deferrals, not on actual
+            // message ordering.  We don't care *what* activity is being
+            // launched; only that we're doing so.
+            if (mPssDeferralTime > 0) {
+                final Message msg = mBgHandler.obtainMessage(DEFER_PSS_MSG);
+                mBgHandler.sendMessageAtFrontOfQueue(msg);
+            }
+        }
+
+        // The other observer methods are unused
+        @Override
+        public void onIntentStarted(Intent intent) {
+        }
+
+        @Override
+        public void onIntentFailed() {
+        }
+
+        @Override
+        public void onActivityLaunchCancelled(byte[] abortingActivity) {
+        }
+
+        @Override
+        public void onActivityLaunchFinished(byte[] finalActivity) {
+        }
+    };
+
+    /**
+     * How long we defer PSS gathering while activities are starting, in milliseconds.
+     * This is adjustable via DeviceConfig.  If it is zero or negative, no PSS deferral
+     * is done.
+     */
+    private volatile long mPssDeferralTime = 0;
+    private static final String ACTIVITY_START_PSS_DEFER_CONFIG = "activity_start_pss_defer";
+
     private boolean mBinderTransactionTrackingEnabled = false;
 
     /**
@@ -874,6 +922,20 @@
      */
     boolean mFullPssPending = false;
 
+    /**
+     * Observe DeviceConfig changes to the PSS calculation interval
+     */
+    private final DeviceConfig.OnPropertiesChangedListener mPssDelayConfigListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(Properties properties) {
+                    mPssDeferralTime = properties.getLong(ACTIVITY_START_PSS_DEFER_CONFIG, 0);
+                    if (DEBUG_PSS) {
+                        Slog.d(TAG_PSS, "Activity-start PSS delay now "
+                                + mPssDeferralTime + " ms");
+                    }
+                }
+            };
 
     /**
      * This is for verifying the UID report flow.
@@ -1838,6 +1900,8 @@
     }
 
     static final int COLLECT_PSS_BG_MSG = 1;
+    static final int DEFER_PSS_MSG = 2;
+    static final int STOP_DEFERRING_PSS_MSG = 3;
 
     final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
         @Override
@@ -1945,6 +2009,30 @@
                     }
                 } while (true);
             }
+
+            case DEFER_PSS_MSG: {
+                deferPssForActivityStart();
+            } break;
+
+            case STOP_DEFERRING_PSS_MSG: {
+                final int nesting = mActivityStartingNesting.decrementAndGet();
+                if (nesting <= 0) {
+                    if (DEBUG_PSS) {
+                        Slog.d(TAG_PSS, "PSS activity start deferral interval ended; now "
+                                + nesting);
+                    }
+                    if (nesting < 0) {
+                        Slog.wtf(TAG, "Activity start nesting undercount!");
+                        mActivityStartingNesting.incrementAndGet();
+                    }
+                } else {
+                    if (DEBUG_PSS) {
+                        Slog.d(TAG_PSS, "Still deferring PSS, nesting=" + nesting);
+                    }
+                }
+            }
+            break;
+
             }
         }
     };
@@ -8845,6 +8933,12 @@
                 NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
         mHiddenApiBlacklist.registerObserver();
 
+        final long pssDeferralMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                ACTIVITY_START_PSS_DEFER_CONFIG, 0L);
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                ActivityThread.currentApplication().getMainExecutor(),
+                mPssDelayConfigListener);
+
         synchronized (this) {
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
@@ -8861,6 +8955,7 @@
                     com.android.internal.R.bool.config_multiuserDelayUserDataLocking);
 
             mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
+            mPssDeferralTime = pssDeferralMs;
         }
     }
 
@@ -8923,6 +9018,7 @@
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());
 
         mAtmInternal.updateTopComponentForFactoryTest();
+        mAtmInternal.getLaunchObserverRegistry().registerLaunchObserver(mActivityLaunchObserver);
 
         watchDeviceProvisioning(mContext);
 
@@ -16146,7 +16242,13 @@
             return false;
         }
         if (mPendingPssProcesses.size() == 0) {
-            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+            final long deferral = (mPssDeferralTime > 0 && mActivityStartingNesting.get() > 0)
+                    ? mPssDeferralTime : 0;
+            if (DEBUG_PSS && deferral > 0) {
+                Slog.d(TAG_PSS, "requestPssLocked() deferring PSS request by "
+                        + deferral + " ms");
+            }
+            mBgHandler.sendEmptyMessageDelayed(COLLECT_PSS_BG_MSG, deferral);
         }
         if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of: " + proc);
         proc.pssProcState = procState;
@@ -16156,6 +16258,30 @@
     }
 
     /**
+     * Re-defer a posted PSS collection pass, if one exists.  Assumes deferral is
+     * currently active policy when called.
+     */
+    private void deferPssIfNeededLocked() {
+        if (mPendingPssProcesses.size() > 0) {
+            mBgHandler.removeMessages(COLLECT_PSS_BG_MSG);
+            mBgHandler.sendEmptyMessageDelayed(COLLECT_PSS_BG_MSG, mPssDeferralTime);
+        }
+    }
+
+    private void deferPssForActivityStart() {
+        synchronized (ActivityManagerService.this) {
+            if (mPssDeferralTime > 0) {
+                if (DEBUG_PSS) {
+                    Slog.d(TAG_PSS, "Deferring PSS collection for activity start");
+                }
+                deferPssIfNeededLocked();
+                mActivityStartingNesting.getAndIncrement();
+                mBgHandler.sendEmptyMessageDelayed(STOP_DEFERRING_PSS_MSG, mPssDeferralTime);
+            }
+        }
+    }
+
+    /**
      * Schedule PSS collection of all processes.
      */
     void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 5ade50a..bcfe71b8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -431,7 +431,7 @@
             for (int i = 0; i < N; i++) {
                 ProcessRecord app = mProcessList.mLruProcesses.get(i);
                 if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
-                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now,
+                    if (computeOomAdjLocked(app, app.getCurRawAdj(), TOP_APP, true, now,
                             true)) {
                         retryCycles = true;
                     }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 3a78aa2..037293f 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -50,6 +50,7 @@
 import android.provider.Telephony;
 import android.telecom.TelecomManager;
 import android.util.ArraySet;
+import android.util.LongSparseLongArray;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -58,6 +59,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.IntPair;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
@@ -147,11 +149,9 @@
                 PermissionInfo perm = dangerousPerms.get(i);
 
                 if (perm.isHardRestricted() || perm.backgroundPermission != null) {
-                    appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
-                            null, appOpsListener);
+                    appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
                 } else if (perm.isSoftRestricted()) {
-                    appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
-                            null, appOpsListener);
+                    appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
 
                     SoftRestrictedPermissionPolicy policy =
                             SoftRestrictedPermissionPolicy.forPermission(null, null, null,
@@ -167,6 +167,25 @@
         }
     }
 
+    /**
+     * Get op that controls the access related to the permission.
+     *
+     * <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location)
+     * {@link AppOpsManager#sOpToSwitch share an op} to control the access.
+     *
+     * @param permission The permission
+     *
+     * @return The op that controls the access of the permission
+     */
+    private static int getSwitchOp(@NonNull String permission) {
+        int op = AppOpsManager.permissionToOpCode(permission);
+        if (op == OP_NONE) {
+            return OP_NONE;
+        }
+
+        return AppOpsManager.opToSwitch(op);
+    }
+
     private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
             @UserIdInt int changedUserId) {
         if (isStarted(changedUserId)) {
@@ -430,40 +449,89 @@
          * <p>This processes ops previously added by {@link #addOpIfRestricted}
          */
         private void syncPackages() {
+            // Remember which ops were already set. This makes sure that we always set the most
+            // permissive mode if two OpChanges are scheduled. This can e.g. happen if two
+            // permissions change the same op. See {@link #getSwitchOp}.
+            LongSparseLongArray alreadySetAppOps = new LongSparseLongArray();
+
             final int allowCount = mOpsToAllow.size();
             for (int i = 0; i < allowCount; i++) {
                 final OpToChange op = mOpsToAllow.get(i);
+
                 setUidModeAllowed(op.code, op.uid, op.packageName);
+                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
+
             final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
             for (int i = 0; i < allowIfDefaultCount; i++) {
                 final OpToChange op = mOpsToAllowIfDefault.get(i);
-                setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
+                boolean wasSet = setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
+                if (wasSet) {
+                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
+                }
             }
-            final int foregroundCount = mOpsToForegroundIfAllow.size();
-            for (int i = 0; i < foregroundCount; i++) {
+
+            final int foregroundIfAllowedCount = mOpsToForegroundIfAllow.size();
+            for (int i = 0; i < foregroundIfAllowedCount; i++) {
                 final OpToChange op = mOpsToForegroundIfAllow.get(i);
-                setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
+                boolean wasSet = setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
+                if (wasSet) {
+                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
+                }
             }
-            final int foregroundIfAllowCount = mOpsToForeground.size();
-            for (int i = 0; i < foregroundIfAllowCount; i++) {
+
+            final int foregroundCount = mOpsToForeground.size();
+            for (int i = 0; i < foregroundCount; i++) {
                 final OpToChange op = mOpsToForeground.get(i);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
                 setUidModeForeground(op.code, op.uid, op.packageName);
+                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
+
             final int ignoreCount = mOpsToIgnore.size();
             for (int i = 0; i < ignoreCount; i++) {
                 final OpToChange op = mOpsToIgnore.get(i);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
                 setUidModeIgnored(op.code, op.uid, op.packageName);
+                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
+
             final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
             for (int i = 0; i < ignoreIfDefaultCount; i++) {
                 final OpToChange op = mOpsToIgnoreIfDefault.get(i);
-                setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
+                boolean wasSet = setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName);
+                if (wasSet) {
+                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
+                }
             }
+
             final int defaultCount = mOpsToDefault.size();
             for (int i = 0; i < defaultCount; i++) {
                 final OpToChange op = mOpsToDefault.get(i);
+                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
+                    continue;
+                }
+
                 setUidModeDefault(op.code, op.uid, op.packageName);
+                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
         }
 
@@ -479,7 +547,7 @@
         private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo,
                 @NonNull PackageInfo pkg) {
             final String permission = permissionInfo.name;
-            final int opCode = AppOpsManager.permissionToOpCode(permission);
+            final int opCode = getSwitchOp(permission);
             final int uid = pkg.applicationInfo.uid;
 
             if (!permissionInfo.isRestricted()) {
@@ -581,7 +649,7 @@
             }
 
             final String permission = permissionInfo.name;
-            final int opCode = AppOpsManager.permissionToOpCode(permission);
+            final int opCode = getSwitchOp(permission);
             final String pkgName = pkg.packageName;
             final int uid = pkg.applicationInfo.uid;
 
@@ -641,7 +709,7 @@
             }
 
             for (String permission : pkg.requestedPermissions) {
-                final int opCode = AppOpsManager.permissionToOpCode(permission);
+                final int opCode = getSwitchOp(permission);
                 if (opCode == OP_NONE) {
                     continue;
                 }
@@ -658,24 +726,27 @@
             }
         }
 
-        private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
-            setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
+        private boolean setUidModeAllowedIfDefault(int opCode, int uid,
+                @NonNull String packageName) {
+            return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
         }
 
         private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
             setUidMode(opCode, uid, MODE_ALLOWED, packageName);
         }
 
-        private void setUidModeForegroundIfAllow(int opCode, int uid, @NonNull String packageName) {
-            setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
+        private boolean setUidModeForegroundIfAllow(int opCode, int uid,
+                @NonNull String packageName) {
+            return setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
         }
 
         private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
             setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
         }
 
-        private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
-            setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
+        private boolean setUidModeIgnoredIfDefault(int opCode, int uid,
+                @NonNull String packageName) {
+            return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
         }
 
         private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
@@ -692,14 +763,17 @@
             }
         }
 
-        private void setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
+        private boolean setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
                 @NonNull String packageName) {
             final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                     .opToPublicName(opCode), uid, packageName);
 
             if (currentMode == requiredModeBefore) {
                 mAppOpsManager.setUidMode(opCode, uid, newMode);
+                return true;
             }
+
+            return false;
         }
 
         private void setUidModeDefault(int opCode, int uid, String packageName) {
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index c7f8c07..c7e241b 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -41,6 +41,9 @@
       "options": [
         {
           "include-filter": "android.permission.cts.SplitPermissionTest"
+        },
+        {
+          "include-filter": "android.permission.cts.BackgroundPermissionsTest"
         }
       ]
     }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index ba23258..af72931 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -25,6 +25,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.NonNull;
 import android.app.RemoteAction;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
@@ -45,6 +46,7 @@
 import android.view.IPinnedStackListener;
 
 import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.internal.util.Preconditions;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
@@ -326,8 +328,8 @@
     boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
         synchronized (mService.mGlobalLock) {
             final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            if (mDisplayInfo.equals(displayInfo)) {
-                // We are already in the right orientation, ignore
+            if (isSameDimensionAndRotation(mDisplayInfo, displayInfo)) {
+                // No dimension/rotation change, ignore
                 outBounds.setEmpty();
                 return false;
             } else if (targetBounds.isEmpty()) {
@@ -427,6 +429,15 @@
         notifyActionsChanged(mActions);
     }
 
+    private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1,
+            @NonNull DisplayInfo display2) {
+        Preconditions.checkNotNull(display1);
+        Preconditions.checkNotNull(display2);
+        return ((display1.rotation == display2.rotation)
+                && (display1.logicalWidth == display2.logicalWidth)
+                && (display1.logicalHeight == display2.logicalHeight));
+    }
+
     /**
      * Notifies listeners that the PIP needs to be adjusted for the IME.
      */