Merge "AudioService: Make suspended apps lose audio focus"
diff --git a/Android.bp b/Android.bp
index 072007b..1ee7405 100644
--- a/Android.bp
+++ b/Android.bp
@@ -773,7 +773,7 @@
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.hardware.wifi-V1.0-java-constants",
-        "networkstack-aidl-interfaces-java",
+        "networkstack-aidl-framework-java",
         "netd_aidl_parcelables-java",
         "devicepolicyprotosnano",
     ],
@@ -896,7 +896,6 @@
         "core/java/android/net/DhcpResultsParcelable.aidl",
         "core/java/android/net/INetworkMonitor.aidl",
         "core/java/android/net/INetworkMonitorCallbacks.aidl",
-        "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
         "core/java/android/net/INetworkStackStatusCallback.aidl",
         "core/java/android/net/InitialConfigurationParcelable.aidl",
@@ -915,6 +914,16 @@
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
         "core/java/android/net/ip/IIpClient.aidl",
         "core/java/android/net/ip/IIpClientCallbacks.aidl",
+    ],
+    api_dir: "aidl/networkstack",
+}
+
+aidl_interface {
+    name: "networkstack-aidl-framework",
+    local_include_dir: "core/java",
+    srcs: [
+        "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
+        "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     api_dir: "aidl/networkstack",
diff --git a/api/current.txt b/api/current.txt
index af8f53f..9cd33e6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2222,6 +2222,7 @@
     field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
     field public static final int Theme = 16973829; // 0x1030005
     field public static final int ThemeOverlay = 16974407; // 0x1030247
+    field public static final int ThemeOverlay_DeviceDefault_Accent_DayNight = 16974564; // 0x10302e4
     field public static final int ThemeOverlay_Material = 16974408; // 0x1030248
     field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
     field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
@@ -2233,6 +2234,7 @@
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
     field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
+    field public static final int Theme_DeviceDefault_DayNight = 16974563; // 0x10302e3
     field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
     field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
     field public static final int Theme_DeviceDefault_DialogWhenLarge_NoActionBar = 16974135; // 0x1030137
diff --git a/api/test-current.txt b/api/test-current.txt
index fecb07a..d91ad44 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -516,13 +516,20 @@
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method @Nullable public abstract String[] getNamesForUids(int[]);
     method public abstract String getPermissionControllerPackageName();
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
     method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
     method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
     method public String getWellbeingPackageName();
     method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
     field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+    field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
+    field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
+    field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
+    field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2
+    field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
     field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
     field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 57c32c7..2632294d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -303,6 +303,7 @@
         DangerousPermissionState dangerous_permission_state = 10050;
         TrainInfo train_info = 10051;
         TimeZoneDataInfo time_zone_data_info = 10052;
+        SDCardInfo sdcard_info = 10053;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -3231,6 +3232,28 @@
     optional int32 cycle_count = 1;
 }
 
+/**
+ * Logs that an SD card is mounted and information about it, its type (public or private) and the
+ * size in bytes.
+ * Pulled from:
+ *   StatsCompanionService
+ */
+
+message SDCardInfo {
+
+    enum Type {
+        UNKNOWN = 0;
+        TYPE_PUBLIC = 1;
+        TYPE_PRIVATE = 2;
+        OTHERS = 3;
+    }
+
+    // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+    optional Type type = 1;
+    // Total size of the sd card in bytes.
+    optional int64 size_bytes = 2;
+}
+
 /*
  * Logs when a connection becomes available and lost.
  * Logged in StatsCompanionService.java
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index d70c851..1513834 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -237,6 +237,9 @@
         // TimeZoneDataInfo.
         {android::util::TIME_ZONE_DATA_INFO,
          {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
+        // SDCardInfo
+        {android::util::SDCARD_INFO,
+         {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5f778da..e55c964 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -71,6 +71,7 @@
 import android.os.Looper;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.StrictMode;
@@ -2297,7 +2298,7 @@
     public final void requestShowKeyboardShortcuts() {
         Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
         intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
-        sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+        sendBroadcastAsUser(intent, Process.myUserHandle());
     }
 
     /**
@@ -2306,7 +2307,7 @@
     public final void dismissKeyboardShortcutsHelper() {
         Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS);
         intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
-        sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+        sendBroadcastAsUser(intent, Process.myUserHandle());
     }
 
     @Override
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 87bf5ed..f116e13 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.pm.ServiceInfo.ForegroundServiceType;
 import android.content.res.Configuration;
 import android.os.Build;
 import android.os.IBinder;
@@ -735,7 +736,7 @@
    * @see {@link android.content.pm.ServiceInfo} for the set of FOREGROUND_SERVICE_TYPE flags.
    */
     public final void startForeground(int id, @NonNull Notification notification,
-            int foregroundServiceType) {
+            @ForegroundServiceType int foregroundServiceType) {
         try {
             mActivityManager.setServiceForeground(
                     new ComponentName(this, mClassName), mToken, id,
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b9f56b1..c12a92f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1129,7 +1129,11 @@
                     IBinder b = ServiceManager
                             .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
                     IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
-                    return new ContentCaptureManager(outerContext, service);
+                    if (service != null) {
+                        // When feature is disabled, we return a null manager to apps so the
+                        // performance impact is practically zero
+                        return new ContentCaptureManager(outerContext, service);
+                    }
                 }
                 return null;
             }});
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 94a2a3e..97efa01 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -465,8 +465,6 @@
                 mActivities.put(instanceId, eventType);
                 break;
             case ACTIVITY_STOPPED:
-                mActivities.put(instanceId, eventType);
-                break;
             case ACTIVITY_DESTROYED:
                 // remove activity from the map.
                 mActivities.delete(instanceId);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 36ffb0e..14e7725 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -295,8 +295,6 @@
     void restoreDefaultApps(in byte[] backup, int userId);
     byte[] getIntentFilterVerificationBackup(int userId);
     void restoreIntentFilterVerification(in byte[] backup, int userId);
-    byte[] getPermissionGrantBackup(int userId);
-    void restorePermissionGrants(in byte[] backup, int userId);
 
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3ea78df..0041921 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2943,6 +2943,7 @@
     * @hide
     */
     @SystemApi
+    @TestApi
     public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
 
     /**
@@ -2953,6 +2954,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int FLAG_PERMISSION_USER_FIXED =  1 << 1;
 
     /**
@@ -2976,6 +2978,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE =  1 << 3;
 
     /**
@@ -3005,6 +3008,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int FLAG_PERMISSION_REVIEW_REQUIRED =  1 << 6;
 
     /**
@@ -3014,6 +3018,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED =  1 << 7;
 
     /**
@@ -3795,6 +3800,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
@@ -3815,6 +3821,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 60475de..4a2f800 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -151,6 +151,7 @@
      * @hide
      */
     @IntDef(flag = true, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = {
+            FOREGROUND_SERVICE_TYPE_MANIFEST,
             FOREGROUND_SERVICE_TYPE_NONE,
             FOREGROUND_SERVICE_TYPE_DATA_SYNC,
             FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
@@ -180,10 +181,10 @@
     }
 
     /**
-     * Return the current foreground service type.
-     * @return the current foreground service type.
+     * Return foreground service type specified in the manifest..
+     * @return foreground service type specified in the manifest.
      */
-    public int getForegroundServiceType() {
+    public @ForegroundServiceType int getForegroundServiceType() {
         return mForegroundServiceType;
     }
 
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 89967c3..addfe3d 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -624,7 +624,7 @@
          *
          * <p>Needs to be called when canceling this task as it might be hung.
          */
-        void interruptRead() {
+        void interruptWrite() {
             IoUtils.closeQuietly(mLocalPipe);
         }
 
@@ -806,18 +806,19 @@
 
         @Override
         public void run(@NonNull IPermissionController service) {
+            mBackupSender.execute(mBackup);
+
             ParcelFileDescriptor remotePipe = mBackupSender.getRemotePipe();
             try {
                 service.restoreRuntimePermissionBackup(mUser, remotePipe);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error sending runtime permission backup", e);
                 mBackupSender.cancel(false);
+                mBackupSender.interruptWrite();
             } finally {
                 // Remote pipe end is duped by binder call. Local copy is not needed anymore
                 IoUtils.closeQuietly(remotePipe);
             }
-
-            mBackupSender.execute(mBackup);
         }
     }
 
diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java
new file mode 100644
index 0000000..92dbab33
--- /dev/null
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.UserHandle;
+
+/**
+ * Internal interfaces to be used by other components within the system server.
+ *
+ * <p>Only for use within the system server.
+ *
+ * @hide
+ */
+public abstract class PermissionManagerInternal {
+    /**
+     * Get the state of the runtime permissions as xml file.
+     *
+     * @param user The user the data should be extracted for
+     *
+     * @return The state as a xml file
+     */
+    public abstract @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user);
+
+    /**
+     * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+     *
+     * <p>If not all state can be restored, the un-restoreable state will be delayed and can be
+     * re-tried via {@link #restoreDelayedRuntimePermissions}.
+     *
+     * @param backup The state as an xml file
+     * @param user The user the data should be restored for
+     */
+    public abstract void restoreRuntimePermissions(@NonNull byte[] backup,
+            @NonNull UserHandle user);
+
+    /**
+     * Try to apply permission backup of a package that was previously not applied.
+     *
+     * @param packageName The package that is newly installed
+     * @param user The user the package is installed for
+     *
+     * @see #restoreRuntimePermissions
+     */
+    public abstract void restoreDelayedRuntimePermissions(@NonNull String packageName,
+            @NonNull UserHandle user);
+}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 634443d..0157d26 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -39,15 +39,8 @@
 
 import java.io.PrintWriter;
 
-/*
- * NOTE: all methods in this class should return right away, or do the real work in a handler
- * thread.
- *
- * Hence, the only field that must be thread-safe is mEnabled, which is called at the beginning
- * of every method.
- */
 /**
- * TODO(b/123577059): add javadocs / implement
+ * TODO(b/123577059): add javadocs / mention it can be null
  */
 @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
 public final class ContentCaptureManager {
@@ -90,7 +83,7 @@
     @NonNull
     private final Context mContext;
 
-    @Nullable
+    @NonNull
     private final IContentCaptureManager mService;
 
     // Flags used for starting session.
@@ -107,11 +100,11 @@
 
     /** @hide */
     public ContentCaptureManager(@NonNull Context context,
-            @Nullable IContentCaptureManager service) {
-        mContext = Preconditions.checkNotNull(context, "context cannot be null");
+            @NonNull IContentCaptureManager service) {
         if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName());
+        mContext = Preconditions.checkNotNull(context, "context cannot be null");
+        mService = Preconditions.checkNotNull(service, "service cannot be null");
 
-        mService = service;
         // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
         // do, then we should optimize it to run the tests after the Choreographer finishes the most
         // important steps of the frame.
@@ -199,8 +192,6 @@
      * </ul>
      */
     public boolean isContentCaptureEnabled() {
-        if (mService == null) return false;
-
         final MainContentCaptureSession mainSession;
         synchronized (mLock) {
             mainSession = mMainSession;
@@ -242,8 +233,6 @@
     @SystemApi
     @TestApi
     public boolean isContentCaptureFeatureEnabled() {
-        if (mService == null) return false;
-
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         final int resultCode;
         try {
@@ -314,22 +303,21 @@
 
     /** @hide */
     public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.println("ContentCaptureManager");
+        final String prefix2 = prefix + "  ";
         synchronized (mLock) {
-            pw.print(prefix); pw.println("ContentCaptureManager");
-            pw.print(prefix); pw.print("isContentCaptureEnabled(): ");
+            pw.print(prefix2); pw.print("isContentCaptureEnabled(): ");
             pw.println(isContentCaptureEnabled());
-            pw.print(prefix); pw.print("Context: "); pw.println(mContext);
-            pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
-            if (mService != null) {
-                pw.print(prefix); pw.print("Service: "); pw.println(mService);
-            }
-            pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+            pw.print(prefix2); pw.print("Context: "); pw.println(mContext);
+            pw.print(prefix2); pw.print("User: "); pw.println(mContext.getUserId());
+            pw.print(prefix2); pw.print("Service: "); pw.println(mService);
+            pw.print(prefix2); pw.print("Flags: "); pw.println(mFlags);
             if (mMainSession != null) {
-                final String prefix2 = prefix + "  ";
-                pw.print(prefix); pw.println("Main session:");
-                mMainSession.dump(prefix2, pw);
+                final String prefix3 = prefix2 + "  ";
+                pw.print(prefix2); pw.println("Main session:");
+                mMainSession.dump(prefix3, pw);
             } else {
-                pw.print(prefix); pw.println("No sessions");
+                pw.print(prefix2); pw.println("No sessions");
             }
         }
     }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index d949f45..f0f2c49 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -105,14 +105,14 @@
      * Interface to the system_server binder object - it's only used to start the session (and
      * notify when the session is finished).
      */
-    @Nullable // TODO(b/122959591): shoul never be null, we should make main session null instead
+    @NonNull
     private final IContentCaptureManager mSystemServerInterface;
 
     /**
      * Direct interface to the service binder object - it's used to send the events, including the
      * last ones (when the session is finished)
      */
-    @Nullable
+    @NonNull
     private IContentCaptureDirectManager mDirectServiceInterface;
     @Nullable
     private DeathRecipient mDirectServiceVulture;
@@ -140,7 +140,7 @@
     /** @hide */
     protected MainContentCaptureSession(@NonNull Context context,
             @NonNull ContentCaptureManager manager, @NonNull Handler handler,
-            @Nullable IContentCaptureManager systemServerInterface) {
+            @NonNull IContentCaptureManager systemServerInterface) {
         mContext = context;
         mManager = manager;
         mHandler = handler;
@@ -193,8 +193,6 @@
         }
 
         try {
-            if (mSystemServerInterface == null) return;
-
             mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
                     new IResultReceiver.Stub() {
                         @Override
@@ -507,8 +505,6 @@
         }
 
         try {
-            if (mSystemServerInterface == null) return;
-
             mSystemServerInterface.finishSession(mId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error destroying system-service session " + mId + " for "
@@ -628,12 +624,11 @@
 
     @Override
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        super.dump(prefix, pw);
+
         pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
         pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
-        if (mSystemServerInterface != null) {
-            pw.print(prefix); pw.print("mSystemServerInterface: ");
-            pw.println(mSystemServerInterface);
-        }
+        pw.print(prefix); pw.print("mSystemServerInterface: ");
         if (mDirectServiceInterface != null) {
             pw.print(prefix); pw.print("mDirectServiceInterface: ");
             pw.println(mDirectServiceInterface);
@@ -667,8 +662,6 @@
         }
         pw.print(prefix); pw.println("flush history:");
         mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
-
-        super.dump(prefix, pw);
     }
 
     /**
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index eef40e1..d037337 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -95,7 +95,7 @@
     public static final int LENGTH_LONG = 1;
 
     final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final TN mTN;
     @UnsupportedAppUsage
     int mDuration;
@@ -354,7 +354,7 @@
     }
 
     private static class TN extends ITransientNotification.Stub {
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
 
         private static final int SHOW = 0;
@@ -362,18 +362,18 @@
         private static final int CANCEL = 2;
         final Handler mHandler;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         int mGravity;
         int mX;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         int mY;
         float mHorizontalMargin;
         float mVerticalMargin;
 
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         View mView;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         View mNextView;
         int mDuration;
 
diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java
index c0ba181..c7c423b 100644
--- a/core/java/com/android/server/backup/PermissionBackupHelper.java
+++ b/core/java/com/android/server/backup/PermissionBackupHelper.java
@@ -16,11 +16,14 @@
 
 package com.android.server.backup;
 
-import android.app.AppGlobals;
+import android.annotation.NonNull;
 import android.app.backup.BlobBackupHelper;
-import android.content.pm.IPackageManager;
+import android.os.UserHandle;
+import android.permission.PermissionManagerInternal;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
+
 public class PermissionBackupHelper extends BlobBackupHelper {
     private static final String TAG = "PermissionBackup";
     private static final boolean DEBUG = false;
@@ -31,24 +34,26 @@
     // key under which the permission-grant state blob is committed to backup
     private static final String KEY_PERMISSIONS = "permissions";
 
-    private final int mUserId;
+    private final @NonNull UserHandle mUser;
+
+    private final @NonNull PermissionManagerInternal mPermissionManager;
 
     public PermissionBackupHelper(int userId) {
         super(STATE_VERSION, KEY_PERMISSIONS);
 
-        mUserId = userId;
+        mUser = UserHandle.of(userId);
+        mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
     }
 
     @Override
     protected byte[] getBackupPayload(String key) {
-        IPackageManager pm = AppGlobals.getPackageManager();
         if (DEBUG) {
             Slog.d(TAG, "Handling backup of " + key);
         }
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    return pm.getPermissionGrantBackup(mUserId);
+                    return mPermissionManager.backupRuntimePermissions(mUser);
 
                 default:
                     Slog.w(TAG, "Unexpected backup key " + key);
@@ -61,14 +66,13 @@
 
     @Override
     protected void applyRestoredPayload(String key, byte[] payload) {
-        IPackageManager pm = AppGlobals.getPackageManager();
         if (DEBUG) {
             Slog.d(TAG, "Handling restore of " + key);
         }
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    pm.restorePermissionGrants(payload, mUserId);
+                    mPermissionManager.restoreRuntimePermissions(payload, mUser);
                     break;
 
                 default:
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index af0b7c3..7406136 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -230,6 +230,7 @@
     ],
 
     static_libs: [
+        "libasync_safe",
         "libgif",
         "libseccomp_policy",
         "libgrallocusage",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a2ed7d3..bd998999 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1918,7 +1918,6 @@
     for (jint i = 0; i < nb; i++) {
         deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
     }
-    env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
 
     // check each address is a string and add device type/address to list for device affinity
     Vector<AudioDeviceTypeAddr> deviceVector;
@@ -1932,6 +1931,7 @@
         AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
         deviceVector.add(dev);
     }
+    env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
 
     status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
     return (jint) nativeToJavaStatus(status);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b36c85d..7b4e4ea 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -25,6 +25,8 @@
 
 #define LOG_TAG "Zygote"
 
+#include <async_safe/log.h>
+
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
 #include <sys/mount.h>
 #include <linux/fs.h>
@@ -303,27 +305,23 @@
   int saved_errno = errno;
 
   while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
-     // Log process-death status that we care about.  In general it is
-     // not safe to call LOG(...) from a signal handler because of
-     // possible reentrancy.  However, we know a priori that the
-     // current implementation of LOG() is safe to call from a SIGCHLD
-     // handler in the zygote process.  If the LOG() implementation
-     // changes its locking strategy or its use of syscalls within the
-     // lazy-init critical section, its use here may become unsafe.
+     // Log process-death status that we care about.
     if (WIFEXITED(status)) {
-      ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+      async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+                            "Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
     } else if (WIFSIGNALED(status)) {
-      ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
-      if (WCOREDUMP(status)) {
-        ALOGI("Process %d dumped core.", pid);
-      }
+      async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+                            "Process %d exited due to signal %d (%s)%s", pid,
+                            WTERMSIG(status), strsignal(WTERMSIG(status)),
+                            WCOREDUMP(status) ? "; core dumped" : "");
     }
 
     // If the just-crashed process is the system_server, bring down zygote
     // so that it is restarted by init and system server will be restarted
     // from there.
     if (pid == gSystemServerPid) {
-      ALOGE("Exit zygote because system server (%d) has terminated", pid);
+      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                            "Exit zygote because system server (pid %d) has terminated", pid);
       kill(getpid(), SIGKILL);
     }
 
@@ -336,14 +334,17 @@
   // Note that we shouldn't consider ECHILD an error because
   // the secondary zygote might have no children left to wait for.
   if (pid < 0 && errno != ECHILD) {
-    ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
+    async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG,
+                          "Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
 
   if (blastulas_removed > 0) {
     if (write(gBlastulaPoolEventFD, &blastulas_removed, sizeof(blastulas_removed)) == -1) {
       // If this write fails something went terribly wrong.  We will now kill
       // the zygote and let the system bring it back up.
-      ALOGE("Zygote failed to write to blastula pool event FD: %s", strerror(errno));
+      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                            "Zygote failed to write to blastula pool event FD: %s",
+                            strerror(errno));
       kill(getpid(), SIGKILL);
     }
   }
@@ -612,7 +613,7 @@
     }
 }
 
-static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
+static void CreatePkgSandboxTarget(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
     // Create /mnt/user/0/package/<package-name>
     userid_t user_id = multiuser_get_user_id(uid);
     std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
@@ -622,7 +623,7 @@
     CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
 
     StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
-    CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
+    CreateDir(pkg_sandbox_dir, 0755, uid, uid, fail_fn);
 }
 
 static void BindMount(const std::string& sourceDir, const std::string& targetDir,
@@ -642,29 +643,98 @@
                                 fail_fn_t fail_fn) {
     std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
             mntSourceRoot.c_str(), dirName, packageName.c_str());
-    CreateDir(mntSourceDir, 0755, uid, uid, fail_fn);
 
     std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
             mntTargetRoot.c_str(), dirName, packageName.c_str());
-    CreateDir(mntTargetDir, 0755, uid, uid, fail_fn);
 
     BindMount(mntSourceDir, mntTargetDir, fail_fn);
 }
 
-
-static void createPkgSpecificDirRoots(const std::string& parentDir,
-                                      bool createSandbox,
-                                      mode_t mode, uid_t uid, gid_t gid,
-                                      fail_fn_t fail_fn) {
-    std::string androidDir = StringPrintf("%s/Android", parentDir.c_str());
-    CreateDir(androidDir, mode, uid, gid, fail_fn);
-    std::vector<std::string> dirs = {"data", "media", "obb"};
-    if (createSandbox) {
-        dirs.push_back("sandbox");
+static void CreateSubDirs(int dirfd, const std::string& parentDirPath,
+                          const std::vector<std::string>& subDirs,
+                          fail_fn_t fail_fn) {
+    for (auto& dirName : subDirs) {
+        struct stat sb;
+        if (TEMP_FAILURE_RETRY(fstatat(dirfd, dirName.c_str(), &sb, 0)) == 0) {
+            if (S_ISDIR(sb.st_mode)) {
+                continue;
+            } else if (TEMP_FAILURE_RETRY(unlinkat(dirfd, dirName.c_str(), 0)) == -1) {
+                fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s",
+                        parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+            }
+        } else if (errno != ENOENT) {
+            fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s",
+                    parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+        }
+        if (TEMP_FAILURE_RETRY(mkdirat(dirfd, dirName.c_str(), 0700)) == -1) {
+            fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s",
+                    parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+        }
     }
-    for (auto& dir : dirs) {
-        std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str());
-        CreateDir(path, mode, uid, gid, fail_fn);
+}
+
+static void EnsurePkgSpecificDirs(const std::string& path,
+                                  const std::vector<std::string>& packageNames,
+                                  bool createSandboxDir,
+                                  fail_fn_t fail_fn) {
+    std::string androidDir = StringPrintf("%s/Android", path.c_str());
+    android::base::unique_fd androidFd(
+            open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+    if (androidFd.get() < 0) {
+        if (errno == ENOENT || errno == ENOTDIR) {
+            if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(androidDir.c_str())) == -1) {
+                fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+                        androidDir.c_str(), strerror(errno)));
+            }
+            if (TEMP_FAILURE_RETRY(mkdir(androidDir.c_str(), 0700)) == -1) {
+                fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
+                        androidDir.c_str(), strerror(errno)));
+            }
+            androidFd.reset(open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+        }
+
+        if (androidFd.get() < 0) {
+            fail_fn(CREATE_ERROR("Failed to open %s: %s", androidDir.c_str(), strerror(errno)));
+        }
+    }
+
+    std::vector<std::string> dataMediaObbDirs = {"data", "media", "obb"};
+    if (createSandboxDir) {
+        dataMediaObbDirs.push_back("sandbox");
+    }
+    CreateSubDirs(androidFd.get(), androidDir, dataMediaObbDirs, fail_fn);
+    if (createSandboxDir) {
+        dataMediaObbDirs.pop_back();
+    }
+    for (auto& dirName : dataMediaObbDirs) {
+        std::string dataDir = StringPrintf("%s/%s", androidDir.c_str(), dirName.c_str());
+        android::base::unique_fd dataFd(
+                openat(androidFd, dirName.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+        if (dataFd.get() < 0) {
+            fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s",
+                    androidDir.c_str(), dirName.c_str(), strerror(errno)));
+        }
+        CreateSubDirs(dataFd.get(), dataDir, packageNames, fail_fn);
+    }
+}
+
+static void CreatePkgSandboxSource(const std::string& sandboxSource, fail_fn_t fail_fn) {
+
+    struct stat sb;
+    if (TEMP_FAILURE_RETRY(stat(sandboxSource.c_str(), &sb)) == 0) {
+        if (S_ISDIR(sb.st_mode)) {
+            return;
+        } else if (TEMP_FAILURE_RETRY(unlink(sandboxSource.c_str())) == -1) {
+            fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+                    sandboxSource.c_str(), strerror(errno)));
+        }
+    } else if (errno != ENOENT) {
+        fail_fn(CREATE_ERROR("Failed to stat %s: %s",
+                sandboxSource.c_str(), strerror(errno)));
+    }
+    if (TEMP_FAILURE_RETRY(mkdir(sandboxSource.c_str(), 0700)) == -1) {
+        fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
+                sandboxSource.c_str(), strerror(errno)));
     }
 }
 
@@ -680,21 +750,21 @@
             StringAppendF(&mntTarget, "/%d", userId);
         }
 
-        if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) {
+        if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) == -1) {
             ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno));
             continue;
         }
 
-        // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox}
-        createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn);
+        // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb}
+        EnsurePkgSpecificDirs(mntSource, packageNames, true, fail_fn);
 
         std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
             mntSource.c_str(), sandboxId.c_str());
-        CreateDir(sandboxSource, 0755, uid, uid, fail_fn);
+        CreatePkgSandboxSource(sandboxSource, fail_fn);
         BindMount(sandboxSource, mntTarget, fail_fn);
 
-        // Create /storage/emulated/0/Android/{data,media,obb}
-        createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn);
+        // Ensure /storage/emulated/0/Android/{data,media,obb}
+        EnsurePkgSpecificDirs(mntTarget, packageNames, false, fail_fn);
         for (auto& package : packageNames) {
             MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn);
             MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn);
@@ -775,15 +845,14 @@
             userid_t user_id = multiuser_get_user_id(uid);
             std::string pkgSandboxDir =
                 StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str());
-            struct stat sb;
             bool sandboxAlreadyCreated = true;
-            if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) {
+            if (TEMP_FAILURE_RETRY(access(pkgSandboxDir.c_str(), F_OK)) == -1) {
                 if (errno == ENOENT) {
                     ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str());
                     sandboxAlreadyCreated = false;
-                    CreatePkgSandbox(uid, package_name, fail_fn);
+                    CreatePkgSandboxTarget(uid, package_name, fail_fn);
                 } else {
-                    fail_fn(CREATE_ERROR("Failed to lstat %s: %s",
+                    fail_fn(CREATE_ERROR("Failed to access %s: %s",
                                          pkgSandboxDir.c_str(), strerror(errno)));
                 }
             }
@@ -794,7 +863,7 @@
                                      pkgSandboxDir.c_str(), strerror(errno)));
             }
 
-            if (access("/storage/obb_mount", F_OK) == 0) {
+            if (TEMP_FAILURE_RETRY(access("/storage/obb_mount", F_OK)) == 0) {
                 if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
                     remove("/storage/obb_mount");
                 }
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 949c12e..0721f6f 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -65,4 +65,7 @@
     <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
 
     <style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault" />
+
+    <style name="ThemeOverlay.DeviceDefault.Accent.DayNight"
+           parent="@style/ThemeOverlay.DeviceDefault.Accent" />
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5e65605..3580dd4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2951,6 +2951,8 @@
     <public-group type="style" first-id="0x010302e2">
         <!-- @hide @SystemApi -->
         <public name="Theme.DeviceDefault.DocumentsUI" />
+        <public name="Theme.DeviceDefault.DayNight" />
+        <public name="ThemeOverlay.DeviceDefault.Accent.DayNight" />
     </public-group>
 
     <public-group type="id" first-id="0x01020046">
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 1603508..194c86c 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1652,6 +1652,7 @@
 
     <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
 
+    <!-- DeviceDefault theme for day/night activities. -->
     <style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault.Light" />
 
     <!-- Theme used for the intent picker activity. -->
@@ -1697,6 +1698,10 @@
         <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
+    <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
+    <style name="ThemeOverlay.DeviceDefault.Accent.DayNight"
+           parent="@style/ThemeOverlay.DeviceDefault.Accent.Light" />
+
     <style name="ThemeOverlay.DeviceDefault.Dark.ActionBar.Accent" parent="ThemeOverlay.Material.Dark.ActionBar">
         <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index aa29174..3dc884e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -17,7 +17,6 @@
 package android.security.keystore;
 
 import android.security.Credentials;
-import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
@@ -204,7 +203,12 @@
                         }
                     }
                 }
-
+                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
+                    if (mKeySizeBits != 168) {
+                        throw new InvalidAlgorithmParameterException(
+                            "3DES key size must be 168 bits.");
+                    }
+                }
                 if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
                     if (mKeySizeBits < 64) {
                         throw new InvalidAlgorithmParameterException(
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 742813e..875b90b 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1647,6 +1647,10 @@
     // The overlay must reside of the product partition or must have existed on the product
     // partition before an upgrade to overlay these resources.
     POLICY_PRODUCT_PARTITION = 0x00000008,
+
+    // The overlay must be signed with the same signature as the actor of the target resource,
+    // which can be separate or the same as the target package with the resource.
+    POLICY_SIGNATURE = 0x00000010,
   };
   uint32_t policy_flags;
 
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index ad25a06..5f324f7 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+
 import android.annotation.UnsupportedAppUsage;
 import android.net.NetworkUtils;
 import android.os.IBinder;
@@ -23,21 +25,19 @@
 import android.util.Log;
 
 import java.io.BufferedInputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.net.Proxy;
-import java.net.URL;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.NoRouteToHostException;
 import java.net.ProtocolException;
+import java.net.Proxy;
+import java.net.URL;
 import java.net.UnknownServiceException;
 import java.util.HashMap;
 import java.util.Map;
-
-import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /** @hide */
 public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -67,6 +67,7 @@
     // from com.squareup.okhttp.internal.http
     private final static int HTTP_TEMP_REDIRECT = 307;
     private final static int MAX_REDIRECTS = 20;
+    private AtomicBoolean mIsConnected = new AtomicBoolean(false);
 
     @UnsupportedAppUsage
     public MediaHTTPConnection() {
@@ -90,6 +91,7 @@
             mAllowCrossDomainRedirect = true;
             mURL = new URL(uri);
             mHeaders = convertHeaderStringToMap(headers);
+            mIsConnected.set(true);
         } catch (MalformedURLException e) {
             return null;
         }
@@ -140,7 +142,14 @@
     @Override
     @UnsupportedAppUsage
     public void disconnect() {
-        teardownConnection();
+        if (mIsConnected.getAndSet(false)) {
+            (new Thread() {
+                @Override
+                public void run() {
+                    teardownConnection();
+                }
+            }).start();
+        }
         mHeaders = null;
         mURL = null;
     }
@@ -325,7 +334,14 @@
     @Override
     @UnsupportedAppUsage
     public int readAt(long offset, int size) {
-        return native_readAt(offset, size);
+        if (!mIsConnected.get()) {
+            return -1;
+        }
+        int result = native_readAt(offset, size);
+        if (!mIsConnected.get()) {
+            return -1;
+        }
+        return result;
     }
 
     private int readAt(long offset, byte[] data, int size) {
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
index 7acdfa1..a71977f 100644
--- a/packages/CaptivePortalLogin/Android.bp
+++ b/packages/CaptivePortalLogin/Android.bp
@@ -18,7 +18,7 @@
     name: "CaptivePortalLogin",
     srcs: ["src/**/*.java"],
     sdk_version: "system_current",
-    certificate: "platform",
+    certificate: "networkstack",
     static_libs: [
         "androidx.legacy_legacy-support-v4",
         "metrics-constants-protos",
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index e15dca0..0894ee5 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -23,8 +23,8 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
+    <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
 
     <application android:label="@string/app_name"
                  android:usesCleartextTraffic="true"
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index d656593..b700bf3 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -35,11 +35,12 @@
 android_app {
     name: "NetworkStack",
     sdk_version: "system_current",
-    certificate: "platform",
+    certificate: "networkstack",
     privileged: true,
     static_libs: [
         "NetworkStackLib"
     ],
+    jarjar_rules: "jarjar-rules-shared.txt",
     manifest: "AndroidManifest.xml",
     required: ["NetworkStackPermissionStub"],
 }
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 860ebfb..0476712 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -24,12 +24,10 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
     <!-- Send latency broadcast as current user -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.NETWORK_STACK" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <application
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
new file mode 100644
index 0000000..a8c712a
--- /dev/null
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -0,0 +1,19 @@
+rule com.android.internal.util.** android.net.networkstack.util.@1
+
+rule android.net.shared.Inet4AddressUtils* android.net.networkstack.shared.Inet4AddressUtils@1
+rule android.net.shared.InetAddressUtils* android.net.networkstack.shared.InetAddressUtils@1
+
+# Ignore DhcpResultsParcelable, but jarjar DhcpResults
+# TODO: move DhcpResults into services.net and delete from here
+rule android.net.DhcpResultsParcelable* @0
+rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
+rule android.net.LocalLog* android.net.networkstack.LocalLog@1
+
+# TODO: remove from framework dependencies, then remove here
+rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
+rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
+
+# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
+rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
+# TODO: move TcpKeepalivePacketData to services.net and delete
+rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
index 96d1a28..97d26c7 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.shared.FdEventsReader;
+import android.net.util.FdEventsReader;
 import android.os.Handler;
 import android.system.Os;
 
diff --git a/core/java/android/net/shared/FdEventsReader.java b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
similarity index 98%
rename from core/java/android/net/shared/FdEventsReader.java
rename to packages/NetworkStack/src/android/net/util/FdEventsReader.java
index bffbfb1..1380ea7 100644
--- a/core/java/android/net/shared/FdEventsReader.java
+++ b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.net.shared;
+package android.net.util;
 
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.util.SocketUtils;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java
index 94b1e9f..4aec6b6 100644
--- a/packages/NetworkStack/src/android/net/util/PacketReader.java
+++ b/packages/NetworkStack/src/android/net/util/PacketReader.java
@@ -18,7 +18,6 @@
 
 import static java.lang.Math.max;
 
-import android.net.shared.FdEventsReader;
 import android.os.Handler;
 import android.system.Os;
 
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkStackPermissionStub/Android.bp
index 94870c9..dd70cf5 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/packages/NetworkStackPermissionStub/Android.bp
@@ -21,7 +21,7 @@
     // a classes.dex.
     srcs: ["src/**/*.java"],
     platform_apis: true,
-    certificate: "platform",
+    certificate: "networkstack",
     privileged: true,
     manifest: "AndroidManifest.xml",
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
index e92b36a..b7f7ad2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
@@ -23,6 +23,10 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
 
 /**
  * Utility class that allows Settings to use SystemUI to relay broadcasts related to pinned slices.
@@ -38,12 +42,22 @@
     public static final String EXTRA_URI = "uri";
     public static final String EXTRA_RECEIVER = "receiver";
     public static final String EXTRA_FILTER = "filter";
+    private static final String TAG = "SliceBroadcastRelay";
 
-    public static void registerReceiver(Context context, Uri registerKey,
+    private static final Set<Uri> sRegisteredUris = new ArraySet<>();
+
+    /**
+     * Associate intent filter/sliceUri with corresponding receiver.
+     */
+    public static void registerReceiver(Context context, Uri sliceUri,
             Class<? extends BroadcastReceiver> receiver, IntentFilter filter) {
+
+        Log.d(TAG, "Registering Uri for broadcast relay: " + sliceUri);
+        sRegisteredUris.add(sliceUri);
+
         Intent registerBroadcast = new Intent(ACTION_REGISTER);
         registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
-        registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
+        registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri,
                 Process.myUserHandle().getIdentifier()));
         registerBroadcast.putExtra(EXTRA_RECEIVER,
                 new ComponentName(context.getPackageName(), receiver.getName()));
@@ -52,12 +66,21 @@
         context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
     }
 
-    public static void unregisterReceivers(Context context, Uri registerKey) {
-        Intent registerBroadcast = new Intent(ACTION_UNREGISTER);
+    /**
+     * Unregisters all receivers for a given slice uri.
+     */
+
+    public static void unregisterReceivers(Context context, Uri sliceUri) {
+        if (!sRegisteredUris.contains(sliceUri)) {
+            return;
+        }
+        Log.d(TAG, "Unregistering uri broadcast relay: " + sliceUri);
+        final Intent registerBroadcast = new Intent(ACTION_UNREGISTER);
         registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
-        registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
+        registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri,
                 Process.myUserHandle().getIdentifier()));
 
         context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
+        sRegisteredUris.remove(sliceUri);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ac2c2c9..43affcd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1065,7 +1065,7 @@
     }
 
     public boolean isSaved() {
-        return networkId != WifiConfiguration.INVALID_NETWORK_ID;
+        return mConfig != null;
     }
 
     public Object getTag() {
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index f1158ef..b7b21fa 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -16,8 +16,8 @@
 -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#4a4a4a" />
+    <solid android:color="#242424" /> <!-- 14% of white -->
     <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
-        android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/>
+        android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding" />
     <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 58fe811..f64a64e6 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -15,6 +15,7 @@
      limitations under the License.
 -->
 
+
 <com.android.systemui.privacy.OngoingPrivacyChip
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/privacy_chip"
@@ -22,47 +23,39 @@
     android:layout_width="wrap_content"
     android:layout_marginLeft="@dimen/ongoing_appops_chip_margin"
     android:layout_marginRight="@dimen/ongoing_appops_chip_margin"
-    android:layout_marginTop="@dimen/ongoing_appops_top_chip_margin"
-    android:layout_marginBottom="@dimen/ongoing_appops_top_chip_margin"
-    android:gravity="center_vertical|center_horizontal"
     android:layout_gravity="center_vertical|start"
+    android:gravity="center_vertical"
     android:orientation="horizontal"
-    android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
-    android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
     android:focusable="true">
 
-        <TextView
-            android:id="@+id/in_use_text"
-            android:layout_height="match_parent"
-            android:layout_width="wrap_content"
-            android:layout_gravity="center_vertical|start"
-            android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
-            android:gravity="center_vertical"
-            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-            android:textColor="@color/status_bar_clock_color"
-            android:text="@string/ongoing_privacy_chip_in_use"
-            />
-
         <LinearLayout
-            android:id="@+id/icons_container"
-            android:layout_height="match_parent"
+            android:id="@+id/background"
+            android:layout_height="@dimen/ongoing_appops_chip_height"
             android:layout_width="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:gravity="center_vertical"
-            />
+        >
+                <LinearLayout
+                    android:id="@+id/icons_container"
+                    android:layout_height="match_parent"
+                    android:layout_width="wrap_content"
+                    android:layout_marginStart="@dimen/ongoing_appops_chip_items_margin"
+                    android:layout_gravity="center_vertical"
+                    android:gravity="center_vertical"
+                    />
 
-        <TextView
-            android:id="@+id/text_container"
-            android:layout_height="match_parent"
-            android:layout_width="wrap_content"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:lines="1"
-            android:layout_gravity="center_vertical|end"
-            android:gravity="center_vertical"
-            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-            android:textColor="@color/status_bar_clock_color"
-            android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed"
-            android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
-        />
+                <TextView
+                    android:id="@+id/text_container"
+                    android:layout_height="match_parent"
+                    android:layout_width="wrap_content"
+                    android:layout_gravity="center_vertical|end"
+                    android:paddingStart="@dimen/ongoing_appops_chip_text_padding"
+                    android:paddingEnd="@dimen/ongoing_appops_chip_text_padding"
+                    android:gravity="center_vertical"
+                    android:singleLine="true"
+                    android:ellipsize="end"
+                    android:lines="1"
+                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+                    android:textSize="@dimen/ongoing_appops_chip_text_size"
+                    android:textColor="@color/status_bar_clock_color"
+                />
+          </LinearLayout>
 </com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index df858f0..bb0c6f6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -34,5 +34,4 @@
     <bool name="quick_settings_wide">true</bool>
     <dimen name="qs_detail_margin_top">0dp</dimen>
     <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
-    <dimen name="ongoing_appops_top_chip_margin">2dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1e1245f..1c7ee36 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -980,26 +980,32 @@
     <dimen name="ongoing_appops_dialog_items_bottom_margin">24dp</dimen>
     <!-- Top and bottom margin of title in Ongoing App Ops dialog -->
     <dimen name="ongoing_appops_dialog_title_margin_top_bottom">18dp</dimen>
-    <!-- Side margins around the Ongoing App Ops chip-->
-    <dimen name="ongoing_appops_chip_margin">12dp</dimen>
-    <!-- Top and bottom margins around the Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_top_chip_margin">12dp</dimen>
-    <!-- Start and End padding for Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
-    <!-- Padding between background of Ongoing App Ops chip and content -->
-    <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
-    <!-- Margin between icons of Ongoing App Ops chip when QQS-->
-    <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
-    <!-- Margin between icons of Ongoing App Ops chip when QS-->
-    <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen>
-    <!-- Icon size of Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_icon_size">18dp</dimen>
-    <!-- Radius of Ongoing App Ops chip corners -->
-    <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen>
     <!-- Text size for Ongoing App Ops dialog title -->
     <dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
     <!-- Text size for Ongoing App Ops dialog items -->
     <dimen name="ongoing_appops_dialog_item_size">16sp</dimen>
+    <!-- Side margins around the Ongoing App Ops chip-->
+    <dimen name="ongoing_appops_chip_margin">0dp</dimen>
+    <!-- Height of the Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_height">32dp</dimen>
+    <!-- Start and End padding for Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_text_padding">8dp</dimen>
+    <!-- Padding between background of Ongoing App Ops chip and content -->
+    <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
+    <!-- Side padding between background of Ongoing App Ops chip and content -->
+    <dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
+    <!-- Margin between icons of Ongoing App Ops chip when QQS-->
+    <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
+    <!-- Margin between icons of Ongoing App Ops chip when QS-->
+    <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen>
+    <!-- Icon size of Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_icon_size">@*android:dimen/status_bar_icon_size</dimen>
+    <!-- Radius of Ongoing App Ops chip corners -->
+    <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
+    <!-- Size of text of Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_text_size">12sp</dimen>
+    <!-- Margin between items in Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_items_margin">8dp</dimen>
 
     <!-- How much a bubble is elevated -->
     <dimen name="bubble_elevation">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f277c43..3ac7fd4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -724,6 +724,7 @@
     }
 
     private void handleFaceAuthFailed() {
+        setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 6d583df..6bb4fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -41,6 +41,7 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -141,7 +142,7 @@
             StatusBar statusBar, StatusBarStateController statusBarStateController,
             NotificationListener listener) {
         return new NotificationIconAreaController(context, statusBar, statusBarStateController,
-                listener);
+                listener, Dependency.get(NotificationMediaManager.class));
     }
 
     public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 1765dc8..15dc43f 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -16,7 +16,6 @@
 
 import android.content.Context
 import android.util.AttributeSet
-import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
@@ -40,10 +39,12 @@
             context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
     private val iconColor = context.resources.getColor(
             R.color.status_bar_clock_color, context.theme)
+    private val sidePadding =
+            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
     private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
     private lateinit var text: TextView
     private lateinit var iconsContainer: LinearLayout
-    private lateinit var inUseText: TextView
+    private lateinit var back: LinearLayout
     var expanded = false
         set(value) {
             if (value != field) {
@@ -64,15 +65,15 @@
     override fun onFinishInflate() {
         super.onFinishInflate()
 
-        inUseText = findViewById(R.id.in_use_text)
+        back = findViewById(R.id.background)
         text = findViewById(R.id.text_container)
         iconsContainer = findViewById(R.id.icons_container)
     }
 
     // Should only be called if the builder icons or app changed
     private fun updateView() {
-        inUseText.visibility = if (expanded) View.GONE else View.VISIBLE
-        background = if (expanded) backgroundDrawable else null
+        back.background = if (expanded) backgroundDrawable else null
+        back.setPaddingRelative(0, 0, if (expanded) sidePadding else 0, 0)
         fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
             iconsContainer.removeAllViews()
             dialogBuilder.generateIcons().forEachIndexed { i, it ->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index c0f87cb..6a8c19a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -81,6 +81,7 @@
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -200,6 +201,8 @@
         mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
         mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
         StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
+        // Ignore privacy icons because they show in the space above QQS
+        iconContainer.addIgnoredSlots(getIgnoredIconSlots());
         iconContainer.setShouldRestrictIcons(false);
         mIconManager = new TintedIconManager(iconContainer);
 
@@ -241,6 +244,18 @@
         updateShowPercent();
     }
 
+    private List<String> getIgnoredIconSlots() {
+        ArrayList<String> ignored = new ArrayList<>();
+        ignored.add(mContext.getResources().getString(
+                com.android.internal.R.string.status_bar_camera));
+        ignored.add(mContext.getResources().getString(
+                com.android.internal.R.string.status_bar_microphone));
+        ignored.add(mContext.getResources().getString(
+                com.android.internal.R.string.status_bar_location));
+
+        return ignored;
+    }
+
     private void updateStatusText() {
         boolean changed = updateRingerStatus() || updateAlarmStatus();
 
@@ -372,15 +387,6 @@
 
         setLayoutParams(lp);
 
-        if (mPrivacyChip != null) {
-            MarginLayoutParams lm = (MarginLayoutParams) mPrivacyChip.getLayoutParams();
-            int sideMargins = lm.leftMargin;
-            int topBottomMargins = resources.getDimensionPixelSize(
-                    R.dimen.ongoing_appops_top_chip_margin);
-            lm.setMargins(sideMargins, topBottomMargins, sideMargins, topBottomMargins);
-            mPrivacyChip.setLayoutParams(lm);
-        }
-
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
         updatePrivacyChipAlphaAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index af442d3..64209a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -114,7 +114,7 @@
         lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
         lp.windowAnimations = 0;
         NavigationBarEdgePanel panel = new NavigationBarEdgePanel(
-                context, (gravity & Gravity.LEFT) != 0);
+                context, (gravity & Gravity.LEFT) == Gravity.LEFT);
         panel.setLayoutParams(lp);
         return panel;
     }
@@ -269,12 +269,21 @@
                 dist));
 
         if (dist < mGestureLength) {
-            setLegProgress(MathUtils.constrainedMap(
+            float calculatedLegProgress = MathUtils.constrainedMap(
                     0f, POINTEDNESS_BEFORE_SNAP_RATIO,
                     mGestureLength * START_POINTING_RATIO, mGestureLength,
-                    dist));
+                    dist);
 
-            mGestureDetected = false;
+            // Blend animated value with drag calculated value, allow the gesture to continue
+            // while the animation is playing with jump cuts in the animation.
+            setLegProgress(MathUtils.lerp(calculatedLegProgress, mLegProgress, mDragProgress));
+
+            if (mGestureDetected) {
+                mGestureDetected = false;
+
+                mLegAnimator.setFloatValues(POINTEDNESS_BEFORE_SNAP_RATIO);
+                mLegAnimator.start();
+            }
         } else {
             if (!mGestureDetected) {
                 performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 62f85fe..99269cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -24,6 +24,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -47,6 +48,7 @@
     private final NotificationEntryManager mEntryManager;
     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
     private final StatusBarStateController mStatusBarStateController;
+    private final NotificationMediaManager mMediaManager;
     @VisibleForTesting
     final NotificationListener.NotificationSettingsListener mSettingsListener =
             new NotificationListener.NotificationSettingsListener() {
@@ -93,13 +95,15 @@
 
     public NotificationIconAreaController(Context context, StatusBar statusBar,
             StatusBarStateController statusBarStateController,
-            NotificationListener notificationListener) {
+            NotificationListener notificationListener,
+            NotificationMediaManager notificationMediaManager) {
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
         mEntryManager = Dependency.get(NotificationEntryManager.class);
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(this);
+        mMediaManager = notificationMediaManager;
         notificationListener.addNotificationSettingsListener(mSettingsListener);
 
         initializeNotificationAreaViews(context);
@@ -192,10 +196,13 @@
 
     protected boolean shouldShowNotificationIcon(NotificationEntry entry,
             boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
-            boolean hideRepliedMessages) {
+            boolean hideRepliedMessages, boolean hideCurrentMedia) {
         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
             return false;
         }
+        if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
+            return false;
+        }
         if (!showLowPriority && !entry.isHighPriority()) {
             return false;
         }
@@ -235,14 +242,16 @@
     private void updateShelfIcons() {
         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
                 true /* showAmbient */, !mFullyDark /* showLowPriority */,
-                false /* hideDismissed */, mFullyDark /* hideRepliedMessages */);
+                false /* hideDismissed */, mFullyDark /* hideRepliedMessages */,
+                mFullyDark /* hideCurrentMedia */);
     }
 
     public void updateStatusBarIcons() {
         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
                 false /* showAmbient */, mShowLowPriority /* showLowPriority */,
                 true /* hideDismissed */,
-                true /* hideRepliedMessages */);
+                true /* hideRepliedMessages */,
+                false /* hideCurrentMedia */);
     }
 
     @VisibleForTesting
@@ -261,7 +270,7 @@
      */
     private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
             NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
-            boolean hideDismissed, boolean hideRepliedMessages) {
+            boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia) {
         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
                 mNotificationScrollLayout.getChildCount());
 
@@ -271,7 +280,7 @@
             if (view instanceof ExpandableNotificationRow) {
                 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
                 if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
-                        hideRepliedMessages)) {
+                        hideRepliedMessages, hideCurrentMedia)) {
                     toShow.add(function.apply(ent));
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 6495910..6e36c01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -38,6 +38,7 @@
 import com.android.systemui.statusbar.notification.stack.ViewState;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A container for Status bar system icons. Limits the number of system icons and handles overflow
@@ -67,6 +68,8 @@
     private ArrayList<StatusIconState> mLayoutStates = new ArrayList<>();
     // So we can count and measure properly
     private ArrayList<View> mMeasureViews = new ArrayList<>();
+    // Any ignored icon will never be added as a child
+    private ArrayList<String> mIgnoredSlots = new ArrayList<>();
 
     public StatusIconContainer(Context context) {
         this(context, null);
@@ -146,7 +149,8 @@
         // Collect all of the views which want to be laid out
         for (int i = 0; i < count; i++) {
             StatusIconDisplayable icon = (StatusIconDisplayable) getChildAt(i);
-            if (icon.isIconVisible() && !icon.isIconBlocked()) {
+            if (icon.isIconVisible() && !icon.isIconBlocked()
+                    && !mIgnoredSlots.contains(icon.getSlot())) {
                 mMeasureViews.add((View) icon);
             }
         }
@@ -205,6 +209,47 @@
     }
 
     /**
+     * Add a name of an icon slot to be ignored. It will not show up nor be measured
+     * @param slotName name of the icon as it exists in
+     * frameworks/base/core/res/res/values/config.xml
+     */
+    public void addIgnoredSlot(String slotName) {
+        addIgnoredSlotInternal(slotName);
+        requestLayout();
+    }
+
+    /**
+     * Add a list of slots to be ignored
+     * @param slots names of the icons to ignore
+     */
+    public void addIgnoredSlots(List<String> slots) {
+        for (String slot : slots) {
+            addIgnoredSlotInternal(slot);
+        }
+
+        requestLayout();
+    }
+
+    private void addIgnoredSlotInternal(String slotName) {
+        if (!mIgnoredSlots.contains(slotName)) {
+            mIgnoredSlots.add(slotName);
+        }
+    }
+
+    /**
+     * Remove a slot from the list of ignored icon slots. It will then be shown when set to visible
+     * by the {@link StatusBarIconController}.
+     * @param slotName name of the icon slot to remove from the ignored list
+     */
+    public void removeIgnoredSlot(String slotName) {
+        if (mIgnoredSlots.contains(slotName)) {
+            mIgnoredSlots.remove(slotName);
+        }
+
+        requestLayout();
+    }
+
+    /**
      * Layout is happening from end -> start
      */
     private void calculateIconTranslations() {
@@ -223,7 +268,8 @@
             StatusIconDisplayable iconView = (StatusIconDisplayable) child;
             StatusIconState childState = getViewStateFromChild(child);
 
-            if (!iconView.isIconVisible() || iconView.isIconBlocked()) {
+            if (!iconView.isIconVisible() || iconView.isIconBlocked()
+                    || mIgnoredSlots.contains(iconView.getSlot())) {
                 childState.visibleState = STATE_HIDDEN;
                 if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible");
                 continue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 608dd8b..120d0b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -29,6 +29,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationMediaManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,6 +48,8 @@
     StatusBar mStatusBar;
     @Mock
     StatusBarStateController mStatusBarStateController;
+    @Mock
+    private NotificationMediaManager mMediaManager;
     private NotificationIconAreaController mController;
 
     @Before
@@ -54,7 +57,7 @@
         MockitoAnnotations.initMocks(this);
 
         mController = new NotificationIconAreaController(mContext, mStatusBar,
-                mStatusBarStateController, mListener);
+                mStatusBarStateController, mListener, mMediaManager);
     }
 
     @Test
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 4dcc9ed..5989a46 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2801,8 +2801,7 @@
         } catch (RemoteException e) {
             // if the remote process registering the listener is already dead, just swallow the
             // exception and return
-            Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.",
-                    e);
+            Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", e);
             return false;
         }
     }
@@ -2815,8 +2814,7 @@
         } catch (NoSuchElementException e) {
             // if the death callback isn't connected (it should be...), log error,
             // swallow the exception and return
-            Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.",
-                    e);
+            Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", e);
             return false;
         }
     }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index f293328..47c9b86 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -104,8 +104,7 @@
 
     @Override
     public void onSwitchUser(int userId) {
-        cancelAndUnbindLocked(peekUserStateLocked(userId),
-                AttentionService.ATTENTION_FAILURE_UNKNOWN);
+        cancelAndUnbindLocked(peekUserStateLocked(userId));
     }
 
     /** Resolves and sets up the attention service if it had not been done yet. */
@@ -152,7 +151,8 @@
         }
 
         synchronized (mLock) {
-            unbindAfterTimeoutLocked();
+            final long now = SystemClock.uptimeMillis();
+            freeIfInactiveLocked();
 
             final UserState userState = getOrCreateCurrentUserStateLocked();
             // lazily start the service, which should be very lightweight to start
@@ -172,7 +172,7 @@
                 try {
                     // throttle frequent requests
                     final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache;
-                    if (attentionCheckCache != null && SystemClock.uptimeMillis()
+                    if (attentionCheckCache != null && now
                             < attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) {
                         callback.onSuccess(requestCode, attentionCheckCache.mResult,
                                 attentionCheckCache.mTimestamp);
@@ -190,6 +190,7 @@
                                 userState.mAttentionCheckCache = new AttentionCheckCache(
                                         SystemClock.uptimeMillis(), result,
                                         timestamp);
+                                userState.mCurrentAttentionCheckIsFulfilled = true;
                             }
                             StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
                                     result);
@@ -198,6 +199,7 @@
                         @Override
                         public void onFailure(int requestCode, int error) {
                             callback.onFailure(requestCode, error);
+                            userState.mCurrentAttentionCheckIsFulfilled = true;
                             StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
                                     error);
                         }
@@ -214,7 +216,10 @@
     /** Cancels the specified attention check. */
     public void cancelAttentionCheck(int requestCode) {
         synchronized (mLock) {
-            final UserState userState = getOrCreateCurrentUserStateLocked();
+            final UserState userState = peekCurrentUserStateLocked();
+            if (userState == null) {
+                return;
+            }
             if (userState.mService == null) {
                 if (userState.mPendingAttentionCheck != null
                         && userState.mPendingAttentionCheck.mRequestCode == requestCode) {
@@ -231,8 +236,12 @@
     }
 
     @GuardedBy("mLock")
-    private void unbindAfterTimeoutLocked() {
-        mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED,
+    private void freeIfInactiveLocked() {
+        // If we are called here, it means someone used the API again - reset the timer then.
+        mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
+
+        // Schedule resources cleanup if no one calls the API again.
+        mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION,
                 CONNECTION_TTL_MILLIS);
     }
 
@@ -259,12 +268,14 @@
     }
 
     @GuardedBy("mLock")
-    UserState peekCurrentUserStateLocked() {
+    @Nullable
+    private UserState peekCurrentUserStateLocked() {
         return peekUserStateLocked(ActivityManager.getCurrentUser());
     }
 
     @GuardedBy("mLock")
-    UserState peekUserStateLocked(int userId) {
+    @Nullable
+    private UserState peekUserStateLocked(int userId) {
         return mUserStates.get(userId);
     }
 
@@ -401,6 +412,8 @@
         @GuardedBy("mLock")
         int mCurrentAttentionCheckRequestCode;
         @GuardedBy("mLock")
+        boolean mCurrentAttentionCheckIsFulfilled;
+        @GuardedBy("mLock")
         PendingAttentionCheck mPendingAttentionCheck;
 
         @GuardedBy("mLock")
@@ -496,7 +509,7 @@
     }
 
     private class AttentionHandler extends Handler {
-        private static final int CONNECTION_EXPIRED = 1;
+        private static final int CHECK_CONNECTION_EXPIRATION = 1;
         private static final int ATTENTION_CHECK_TIMEOUT = 2;
 
         AttentionHandler() {
@@ -506,19 +519,26 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 // Do not occupy resources when not in use - unbind proactively.
-                case CONNECTION_EXPIRED: {
+                case CHECK_CONNECTION_EXPIRATION: {
                     for (int i = 0; i < mUserStates.size(); i++) {
-                        cancelAndUnbindLocked(mUserStates.valueAt(i),
-                                AttentionService.ATTENTION_FAILURE_UNKNOWN);
+                        cancelAndUnbindLocked(mUserStates.valueAt(i));
                     }
-
                 }
                 break;
 
                 // Callee is no longer interested in the attention check result - cancel.
                 case ATTENTION_CHECK_TIMEOUT: {
-                    cancelAndUnbindLocked(peekCurrentUserStateLocked(),
-                            AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+                    synchronized (mLock) {
+                        final UserState userState = peekCurrentUserStateLocked();
+                        if (userState != null) {
+                            // If not called back already.
+                            if (!userState.mCurrentAttentionCheckIsFulfilled) {
+                                cancel(userState,
+                                        AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+                            }
+
+                        }
+                    }
                 }
                 break;
 
@@ -528,25 +548,29 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void cancelAndUnbindLocked(UserState userState,
-            @AttentionFailureCodes int failureCode) {
-        synchronized (mLock) {
-            if (userState != null && userState.mService != null) {
-                try {
-                    userState.mService.cancelAttentionCheck(
-                            userState.mCurrentAttentionCheckRequestCode);
-                } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Unable to cancel attention check");
-                }
-
-                if (userState.mPendingAttentionCheck != null) {
-                    userState.mPendingAttentionCheck.cancel(failureCode);
-                }
-                mContext.unbindService(userState.mConnection);
-                userState.mConnection.cleanupService();
-                mUserStates.remove(userState.mUserId);
+    private void cancel(UserState userState, @AttentionFailureCodes int failureCode) {
+        if (userState != null && userState.mService != null) {
+            try {
+                userState.mService.cancelAttentionCheck(
+                        userState.mCurrentAttentionCheckRequestCode);
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "Unable to cancel attention check");
             }
+
+            if (userState.mPendingAttentionCheck != null) {
+                userState.mPendingAttentionCheck.cancel(failureCode);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void cancelAndUnbindLocked(UserState userState) {
+        synchronized (mLock) {
+            cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
+
+            mContext.unbindService(userState.mConnection);
+            userState.mConnection.cleanupService();
+            mUserStates.remove(userState.mUserId);
         }
     }
 
@@ -558,8 +582,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
-                cancelAndUnbindLocked(peekCurrentUserStateLocked(),
-                        AttentionService.ATTENTION_FAILURE_UNKNOWN);
+                cancelAndUnbindLocked(peekCurrentUserStateLocked());
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 45f169c..7dd3b36 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -129,240 +129,9 @@
     private final NightDisplayTintController mNightDisplayTintController =
             new NightDisplayTintController();
 
-    private final TintController mDisplayWhiteBalanceTintController = new TintController() {
-        // Three chromaticity coordinates per color: X, Y, and Z
-        private final int NUM_VALUES_PER_PRIMARY = 3;
-        // Four colors: red, green, blue, and white
-        private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
-
-        private final Object mLock = new Object();
-        private int mTemperatureMin;
-        private int mTemperatureMax;
-        private int mTemperatureDefault;
-        private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
-        private ColorSpace.Rgb mDisplayColorSpaceRGB;
-        private float[] mChromaticAdaptationMatrix;
-        private int mCurrentColorTemperature;
-        private float[] mCurrentColorTemperatureXYZ;
-        private boolean mSetUp = false;
-        private float[] mMatrixDisplayWhiteBalance = new float[16];
-        private Boolean mIsAvailable;
-
-        @Override
-        public void setUp(Context context, boolean needsLinear) {
-            mSetUp = false;
-            final Resources res = context.getResources();
-
-            ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
-            if (displayColorSpaceRGB == null) {
-                Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
-                displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
-                if (displayColorSpaceRGB == null) {
-                    Slog.e(TAG, "Failed to get display color space from resources");
-                    return;
-                }
-            }
-
-            final String[] nominalWhiteValues = res.getStringArray(
-                    R.array.config_displayWhiteBalanceDisplayNominalWhite);
-            float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
-            for (int i = 0; i < nominalWhiteValues.length; i++) {
-                displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
-            }
-
-            final int colorTemperatureMin = res.getInteger(
-                    R.integer.config_displayWhiteBalanceColorTemperatureMin);
-            if (colorTemperatureMin <= 0) {
-                Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
-                return;
-            }
-
-            final int colorTemperatureMax = res.getInteger(
-                    R.integer.config_displayWhiteBalanceColorTemperatureMax);
-            if (colorTemperatureMax < colorTemperatureMin) {
-                Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
-                return;
-            }
-
-            final int colorTemperature = res.getInteger(
-                    R.integer.config_displayWhiteBalanceColorTemperatureDefault);
-
-            synchronized (mLock) {
-                mDisplayColorSpaceRGB = displayColorSpaceRGB;
-                mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
-                mTemperatureMin = colorTemperatureMin;
-                mTemperatureMax = colorTemperatureMax;
-                mTemperatureDefault = colorTemperature;
-                mSetUp = true;
-            }
-
-            setMatrix(mTemperatureDefault);
-        }
-
-        @Override
-        public float[] getMatrix() {
-            return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
-        }
-
-        @Override
-        public void setMatrix(int cct) {
-            if (!mSetUp) {
-                Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
-                return;
-            }
-
-            if (cct < mTemperatureMin) {
-                Slog.w(TAG, "Requested display color temperature is below allowed minimum");
-                cct = mTemperatureMin;
-            } else if (cct > mTemperatureMax) {
-                Slog.w(TAG, "Requested display color temperature is above allowed maximum");
-                cct = mTemperatureMax;
-            }
-
-            Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
-
-            synchronized (mLock) {
-                mCurrentColorTemperature = cct;
-
-                // Adapt the display's nominal white point to match the requested CCT value
-                mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
-
-                mChromaticAdaptationMatrix =
-                        ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
-                                mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
-                // Convert the adaptation matrix to RGB space
-                float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
-                        mDisplayColorSpaceRGB.getTransform());
-                result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
-                // Normalize the transform matrix to peak white value in RGB space
-                final float adaptedMaxR = result[0] + result[3] + result[6];
-                final float adaptedMaxG = result[1] + result[4] + result[7];
-                final float adaptedMaxB = result[2] + result[5] + result[8];
-                final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
-                for (int i = 0; i < result.length; i++) {
-                    result[i] /= denum;
-                }
-
-                Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
-                java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
-                java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
-                java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
-            }
-        }
-
-        @Override
-        public int getLevel() {
-            return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
-        }
-
-        @Override
-        public boolean isAvailable(Context context) {
-            if (mIsAvailable == null) {
-                mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
-            }
-            return mIsAvailable;
-        }
-
-        /**
-         * Format a given matrix into a string.
-         *
-         * @param matrix the matrix to format
-         * @param cols number of columns in the matrix
-         */
-        private String matrixToString(float[] matrix, int cols) {
-            if (matrix == null || cols <= 0) {
-                Slog.e(TAG, "Invalid arguments when formatting matrix to string");
-                return "";
-            }
-
-            StringBuilder sb = new StringBuilder("");
-            for (int i = 0; i < matrix.length; i++) {
-                if (i % cols == 0) {
-                    sb.append("\n    ");
-                }
-                sb.append(String.format("%9.6f ", matrix[i]));
-            }
-            return sb.toString();
-        }
-
-        @Override
-        public void dump(PrintWriter pw) {
-            synchronized (mLock) {
-                pw.println("  mSetUp = " + mSetUp);
-                if (!mSetUp) {
-                    return;
-                }
-
-                pw.println("  isActivated = " + isActivated());
-                pw.println("  mTemperatureMin = " + mTemperatureMin);
-                pw.println("  mTemperatureMax = " + mTemperatureMax);
-                pw.println("  mTemperatureDefault = " + mTemperatureDefault);
-                pw.println("  mCurrentColorTemperature = " + mCurrentColorTemperature);
-                pw.println("  mCurrentColorTemperatureXYZ = " +
-                        matrixToString(mCurrentColorTemperatureXYZ, 3));
-                pw.println("  mDisplayColorSpaceRGB RGB-to-XYZ = " +
-                        matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
-                pw.println("  mChromaticAdaptationMatrix = " +
-                        matrixToString(mChromaticAdaptationMatrix, 3));
-                pw.println("  mDisplayColorSpaceRGB XYZ-to-RGB = " +
-                        matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
-                pw.println("  mMatrixDisplayWhiteBalance = " +
-                        matrixToString(mMatrixDisplayWhiteBalance, 4));
-            }
-        }
-
-        private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
-            return new ColorSpace.Rgb(
-                "Display Color Space",
-                redGreenBlueXYZ,
-                whiteXYZ,
-                2.2f // gamma, unused for display white balance
-            );
-        }
-
-        private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
-            final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-            if (displayToken == null) {
-                return null;
-            }
-
-            DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
-            if (primaries == null || primaries.red == null || primaries.green == null ||
-                primaries.blue == null || primaries.white == null) {
-                return null;
-            }
-
-            return makeRgbColorSpaceFromXYZ(
-                    new float[] {
-                        primaries.red.X, primaries.red.Y, primaries.red.Z,
-                        primaries.green.X, primaries.green.Y, primaries.green.Z,
-                        primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
-                    },
-                    new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
-                    );
-        }
-
-        private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
-            final String[] displayPrimariesValues = res.getStringArray(
-                    R.array.config_displayWhiteBalanceDisplayPrimaries);
-            float[] displayRedGreenBlueXYZ =
-                    new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
-            float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
-
-            for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
-                displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
-            }
-
-            for (int i = 0; i < displayWhiteXYZ.length; i++) {
-                displayWhiteXYZ[i] = Float.parseFloat(
-                        displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
-            }
-
-            return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
-        }
-    };
+    @VisibleForTesting
+    final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
+            new DisplayWhiteBalanceTintController();
 
     private final TintController mGlobalSaturationTintController = new TintController() {
 
@@ -860,7 +629,8 @@
         return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
     }
 
-    private void updateDisplayWhiteBalanceStatus() {
+    @VisibleForTesting
+    void updateDisplayWhiteBalanceStatus() {
         boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
         mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
                 !mNightDisplayTintController.isActivated() &&
@@ -1101,6 +871,7 @@
         pw.println("Display white balance:");
         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
             pw.println("    Activated: " + mDisplayWhiteBalanceTintController.isActivated());
+            mDisplayWhiteBalanceTintController.dump(pw);
         } else {
             pw.println("    Not available");
         }
@@ -1533,6 +1304,244 @@
         }
     }
 
+    final class DisplayWhiteBalanceTintController extends TintController {
+        // Three chromaticity coordinates per color: X, Y, and Z
+        private final int NUM_VALUES_PER_PRIMARY = 3;
+        // Four colors: red, green, blue, and white
+        private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+
+        private final Object mLock = new Object();
+        @VisibleForTesting
+        int mTemperatureMin;
+        @VisibleForTesting
+        int mTemperatureMax;
+        private int mTemperatureDefault;
+        private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+        @VisibleForTesting
+        ColorSpace.Rgb mDisplayColorSpaceRGB;
+        private float[] mChromaticAdaptationMatrix;
+        @VisibleForTesting
+        int mCurrentColorTemperature;
+        private float[] mCurrentColorTemperatureXYZ;
+        private boolean mSetUp = false;
+        private float[] mMatrixDisplayWhiteBalance = new float[16];
+        private Boolean mIsAvailable;
+
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+            mSetUp = false;
+            final Resources res = context.getResources();
+
+            ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
+            if (displayColorSpaceRGB == null) {
+                Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
+                displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
+                if (displayColorSpaceRGB == null) {
+                    Slog.e(TAG, "Failed to get display color space from resources");
+                    return;
+                }
+            }
+
+            final String[] nominalWhiteValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayNominalWhite);
+            float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+            for (int i = 0; i < nominalWhiteValues.length; i++) {
+                displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+            }
+
+            final int colorTemperatureMin = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMin);
+            if (colorTemperatureMin <= 0) {
+                Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
+                return;
+            }
+
+            final int colorTemperatureMax = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMax);
+            if (colorTemperatureMax < colorTemperatureMin) {
+                Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
+                return;
+            }
+
+            final int colorTemperature = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+            synchronized (mLock) {
+                mDisplayColorSpaceRGB = displayColorSpaceRGB;
+                mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+                mTemperatureMin = colorTemperatureMin;
+                mTemperatureMax = colorTemperatureMax;
+                mTemperatureDefault = colorTemperature;
+                mSetUp = true;
+            }
+
+            setMatrix(mTemperatureDefault);
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+            if (!mSetUp) {
+                Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+                return;
+            }
+
+            if (cct < mTemperatureMin) {
+                Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+                cct = mTemperatureMin;
+            } else if (cct > mTemperatureMax) {
+                Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+                cct = mTemperatureMax;
+            }
+
+            Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+            synchronized (mLock) {
+                mCurrentColorTemperature = cct;
+
+                // Adapt the display's nominal white point to match the requested CCT value
+                mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+                mChromaticAdaptationMatrix =
+                        ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                                mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+                // Convert the adaptation matrix to RGB space
+                float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+                        mDisplayColorSpaceRGB.getTransform());
+                result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+                // Normalize the transform matrix to peak white value in RGB space
+                final float adaptedMaxR = result[0] + result[3] + result[6];
+                final float adaptedMaxG = result[1] + result[4] + result[7];
+                final float adaptedMaxB = result[2] + result[5] + result[8];
+                final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+                for (int i = 0; i < result.length; i++) {
+                    result[i] /= denum;
+                }
+
+                Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+                java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+                java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+                java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+            }
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+        }
+
+        @Override
+        public boolean isAvailable(Context context) {
+            if (mIsAvailable == null) {
+                mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
+            }
+            return mIsAvailable;
+        }
+
+        /**
+         * Format a given matrix into a string.
+         *
+         * @param matrix the matrix to format
+         * @param cols number of columns in the matrix
+         */
+        private String matrixToString(float[] matrix, int cols) {
+            if (matrix == null || cols <= 0) {
+                Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+                return "";
+            }
+
+            StringBuilder sb = new StringBuilder("");
+            for (int i = 0; i < matrix.length; i++) {
+                if (i % cols == 0) {
+                    sb.append("\n      ");
+                }
+                sb.append(String.format("%9.6f ", matrix[i]));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void dump(PrintWriter pw) {
+            synchronized (mLock) {
+                pw.println("    mSetUp = " + mSetUp);
+                if (!mSetUp) {
+                    return;
+                }
+
+                pw.println("    mTemperatureMin = " + mTemperatureMin);
+                pw.println("    mTemperatureMax = " + mTemperatureMax);
+                pw.println("    mTemperatureDefault = " + mTemperatureDefault);
+                pw.println("    mCurrentColorTemperature = " + mCurrentColorTemperature);
+                pw.println("    mCurrentColorTemperatureXYZ = " +
+                        matrixToString(mCurrentColorTemperatureXYZ, 3));
+                pw.println("    mDisplayColorSpaceRGB RGB-to-XYZ = " +
+                        matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+                pw.println("    mChromaticAdaptationMatrix = " +
+                        matrixToString(mChromaticAdaptationMatrix, 3));
+                pw.println("    mDisplayColorSpaceRGB XYZ-to-RGB = " +
+                        matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+                pw.println("    mMatrixDisplayWhiteBalance = " +
+                        matrixToString(mMatrixDisplayWhiteBalance, 4));
+            }
+        }
+
+        private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
+            return new ColorSpace.Rgb(
+                "Display Color Space",
+                redGreenBlueXYZ,
+                whiteXYZ,
+                2.2f // gamma, unused for display white balance
+            );
+        }
+
+        private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
+            final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
+            if (displayToken == null) {
+                return null;
+            }
+
+            DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
+            if (primaries == null || primaries.red == null || primaries.green == null ||
+                primaries.blue == null || primaries.white == null) {
+                return null;
+            }
+
+            return makeRgbColorSpaceFromXYZ(
+                    new float[] {
+                        primaries.red.X, primaries.red.Y, primaries.red.Z,
+                        primaries.green.X, primaries.green.Y, primaries.green.Z,
+                        primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
+                    },
+                    new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
+                    );
+        }
+
+        private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
+            final String[] displayPrimariesValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayPrimaries);
+            float[] displayRedGreenBlueXYZ =
+                    new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+            float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+
+            for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+                displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+            }
+
+            for (int i = 0; i < displayWhiteXYZ.length; i++) {
+                displayWhiteXYZ[i] = Float.parseFloat(
+                        displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+            }
+
+            return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
+        }
+    };
+
     /**
      * Local service that allows color transforms to be enabled from other system services.
      */
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e71b156..243b6fe 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -373,6 +373,7 @@
     private final NtpTimeHelper mNtpTimeHelper;
     private final GnssBatchingProvider mGnssBatchingProvider;
     private final GnssGeofenceProvider mGnssGeofenceProvider;
+    // Available only on GNSS HAL 2.0 implementations and later.
     private GnssVisibilityControl mGnssVisibilityControl;
 
     // Handler for processing events
@@ -463,8 +464,8 @@
         }
     };
 
-    // TODO(b/119326010): replace OnSubscriptionsChangedListener with
-    // ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED broadcast reseiver.
+    // TODO: replace OnSubscriptionsChangedListener with ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+    //       broadcast receiver.
     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
             new OnSubscriptionsChangedListener() {
                 @Override
@@ -676,8 +677,7 @@
         mNtpTimeHelper.onNetworkAvailable();
         if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
             if (mSupportsXtra) {
-                // Download only if supported, (prevents an unneccesary on-boot
-                // download)
+                // Download only if supported, (prevents an unnecessary on-boot download)
                 xtraDownloadRequest();
             }
         }
@@ -764,7 +764,7 @@
 
     /** Returns true if the location request is too frequent. */
     private boolean isRequestLocationRateLimited() {
-        // TODO(b/73198123): implement exponential backoff.
+        // TODO: implement exponential backoff.
         return false;
     }
 
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index c3f25bf..20f872a 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -24,10 +24,13 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.location.LocationManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.StatsLog;
@@ -70,7 +73,7 @@
     private final Handler mHandler;
     private final Context mContext;
 
-    private boolean mIsMasterLocationSettingsEnabled = true;
+    private boolean mIsDeviceLocationSettingsEnabled;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
     private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -88,13 +91,9 @@
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mPackageManager = mContext.getPackageManager();
 
-        // Set to empty proxy app list initially until the configuration properties are loaded.
-        updateNfwLocationAccessProxyAppsInGnssHal();
-
-        // Listen for proxy app package installation, removal events.
-        listenForProxyAppsPackageUpdates();
-
-        // TODO(b/122855984): Handle global location settings on/off.
+        // Complete initialization as the first event to run in mHandler thread. After that,
+        // all object state read/update events run in the mHandler thread.
+        runOnHandler(this::handleInitialize);
     }
 
     void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
@@ -105,10 +104,6 @@
         runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
     }
 
-    void masterLocationSettingsUpdated(boolean enabled) {
-        runOnHandler(() -> handleMasterLocationSettingsUpdated(enabled));
-    }
-
     void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
             String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
             boolean inEmergencyMode, boolean isCachedLocation) {
@@ -117,7 +112,19 @@
                         requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
     }
 
+    private void handleInitialize() {
+        disableNfwLocationAccess(); // Disable until config properties are loaded.
+        listenForProxyAppsPackageUpdates();
+        listenForDeviceLocationSettingsUpdate();
+        mIsDeviceLocationSettingsEnabled = getDeviceLocationSettings();
+    }
+
+    private boolean getDeviceLocationSettings() {
+        return mContext.getSystemService(LocationManager.class).isLocationEnabled();
+    }
+
     private void listenForProxyAppsPackageUpdates() {
+        // Listen for proxy apps package installation, removal events.
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -143,11 +150,22 @@
         }, UserHandle.ALL, intentFilter, null, mHandler);
     }
 
+    private void listenForDeviceLocationSettingsUpdate() {
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
+                true,
+                new ContentObserver(mHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        handleDeviceLocationSettingsUpdated();
+                    }
+                }, UserHandle.USER_ALL);
+    }
+
     private void handleProxyAppPackageUpdate(String pkgName, String action) {
         final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
-        // pkgName is not one of the proxy apps in our list.
         if (locationPermission == null) {
-            return;
+            return; // ignore, pkgName is not one of the proxy apps in our list.
         }
 
         Log.i(TAG, "Proxy app " + pkgName + " package changed: " + action);
@@ -197,15 +215,33 @@
                 return true;
             }
         }
-
         return false;
     }
 
-    private void handleMasterLocationSettingsUpdated(boolean enabled) {
-        mIsMasterLocationSettingsEnabled = enabled;
-        Log.i(TAG, "Master location settings switch changed to "
-                + (enabled ? "enabled" : "disabled"));
-        updateNfwLocationAccessProxyAppsInGnssHal();
+    private void handleDeviceLocationSettingsUpdated() {
+        final boolean enabled = getDeviceLocationSettings();
+        Log.i(TAG, "Device location settings enabled: " + enabled);
+
+        if (mIsDeviceLocationSettingsEnabled == enabled) {
+            return;
+        }
+
+        mIsDeviceLocationSettingsEnabled = enabled;
+        if (!mIsDeviceLocationSettingsEnabled) {
+            disableNfwLocationAccess();
+            return;
+        }
+
+        // When device location settings was disabled, we already set the proxy app list
+        // to empty in GNSS HAL. Update only if the proxy app list is not empty.
+        String[] locationPermissionEnabledProxyApps = getLocationPermissionEnabledProxyApps();
+        if (locationPermissionEnabledProxyApps.length != 0) {
+            setNfwLocationAccessProxyAppsInGnssHal(locationPermissionEnabledProxyApps);
+        }
+    }
+
+    private void disableNfwLocationAccess() {
+        setNfwLocationAccessProxyAppsInGnssHal(NO_LOCATION_ENABLED_PROXY_APPS);
     }
 
     // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
@@ -316,8 +352,7 @@
             return mPackageManager.getApplicationInfo(pkgName, 0).uid;
         } catch (PackageManager.NameNotFoundException e) {
             if (DEBUG) {
-                Log.d(TAG, "Non-framework location access proxy app "
-                        + pkgName + " is not found.");
+                Log.d(TAG, "Non-framework location access proxy app " + pkgName + " is not found.");
             }
             return null;
         }
@@ -329,8 +364,14 @@
     }
 
     private void updateNfwLocationAccessProxyAppsInGnssHal() {
-        final String[] locationPermissionEnabledProxyApps = shouldDisableNfwLocationAccess()
-                ? NO_LOCATION_ENABLED_PROXY_APPS : getLocationPermissionEnabledProxyApps();
+        if (!mIsDeviceLocationSettingsEnabled) {
+            return; // Keep non-framework location access disabled.
+        }
+        setNfwLocationAccessProxyAppsInGnssHal(getLocationPermissionEnabledProxyApps());
+    }
+
+    private void setNfwLocationAccessProxyAppsInGnssHal(
+            String[] locationPermissionEnabledProxyApps) {
         final String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
         Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
                 + proxyAppsStr);
@@ -341,12 +382,8 @@
         }
     }
 
-    private boolean shouldDisableNfwLocationAccess() {
-        return !mIsMasterLocationSettingsEnabled;
-    }
-
     private String[] getLocationPermissionEnabledProxyApps() {
-        // Get a count of proxy apps with location permission enabled to array creation size.
+        // Get a count of proxy apps with location permission enabled for array creation size.
         int countLocationPermissionEnabledProxyApps = 0;
         for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
             if (hasLocationPermissionEnabled) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index e479a15..d0c59c1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -320,6 +320,11 @@
     private final class PackageReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+            final String action = intent.getAction();
+            if (action == null) {
+                Slog.e(TAG, "Cannot handle package broadcast with null action");
+                return;
+            }
             final Uri data = intent.getData();
             if (data == null) {
                 Slog.e(TAG, "Cannot handle package broadcast with null data");
@@ -337,7 +342,7 @@
                 userIds = new int[] { UserHandle.getUserId(extraUid) };
             }
 
-            switch (intent.getAction()) {
+            switch (action) {
                 case ACTION_PACKAGE_ADDED:
                     if (replacing) {
                         onPackageUpgraded(packageName, userIds);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8608349..f5d88e3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -84,7 +84,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.IoThread;
 import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import libcore.io.IoUtils;
 
@@ -131,7 +131,7 @@
     private final Context mContext;
     private final PackageManagerService mPm;
     private final StagingManager mStagingManager;
-    private final PermissionManagerInternal mPermissionManager;
+    private final PermissionManagerServiceInternal mPermissionManager;
 
     private AppOpsManager mAppOps;
 
@@ -189,7 +189,7 @@
     public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
         mContext = context;
         mPm = pm;
-        mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
+        mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
 
         mInstallThread = new HandlerThread(TAG);
         mInstallThread.start();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 61a1a2f..b1c186e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -238,7 +238,6 @@
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
-import android.permission.PermissionControllerManager;
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings.Global;
@@ -291,7 +290,6 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.EventLogTags;
@@ -315,9 +313,9 @@
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -371,7 +369,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -445,8 +442,6 @@
     private static final boolean ENABLE_FREE_CACHE_V2 =
             SystemProperties.getBoolean("fw.free_cache_v2", true);
 
-    private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
-
     private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
 
     private static final int RADIO_UID = Process.PHONE_UID;
@@ -940,7 +935,7 @@
 
     // TODO remove this and go through mPermissonManager directly
     final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
-    private final PermissionManagerInternal mPermissionManager;
+    private final PermissionManagerServiceInternal mPermissionManager;
 
     private final ComponentResolver mComponentResolver;
     // List of packages names to keep cached, even if they are uninstalled for all users
@@ -1940,9 +1935,10 @@
                             }
                         }
 
-                        // We may also need to apply pending (restored) runtime
-                        // permission grants within these users.
-                        mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+                        // We may also need to apply pending (restored) runtime permission grants
+                        // within these users.
+                        mPermissionManager.restoreDelayedRuntimePermissions(packageName,
+                                UserHandle.of(userId));
 
                         // Persistent preferred activity might have came into effect due to this
                         // install.
@@ -18825,7 +18821,7 @@
             // permission as requiring a review as this is the initial state.
             int flags = 0;
             if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
-                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
             }
             if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
                 if (hasInstallState) {
@@ -19665,139 +19661,6 @@
     }
 
     @Override
-    public byte[] getPermissionGrantBackup(int userId) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            throw new SecurityException("Only the system may call getPermissionGrantBackup()");
-        }
-
-        AtomicReference<byte[]> backup = new AtomicReference<>();
-        mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
-                UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
-                    synchronized (backup) {
-                        backup.set(b);
-                        backup.notifyAll();
-                    }
-                });
-
-        long start = System.currentTimeMillis();
-        synchronized (backup) {
-            while (backup.get() == null) {
-                long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
-                if (timeLeft <= 0) {
-                    return null;
-                }
-
-                try {
-                    backup.wait(timeLeft);
-                } catch (InterruptedException ignored) {
-                    return null;
-                }
-            }
-        }
-
-        return backup.get();
-    }
-
-    @Override
-    public void restorePermissionGrants(byte[] backup, int userId) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            throw new SecurityException("Only the system may call restorePermissionGrants()");
-        }
-
-        try {
-            final XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
-            restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
-                    (parser1, userId1) -> {
-                        synchronized (mPackages) {
-                            processRestoredPermissionGrantsLPr(parser1, userId1);
-                        }
-                    });
-        } catch (Exception e) {
-            if (DEBUG_BACKUP) {
-                Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
-            }
-        }
-    }
-
-    @GuardedBy("mPackages")
-    private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
-            throws XmlPullParserException, IOException {
-        String pkgName = null;
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            final String tagName = parser.getName();
-            if (tagName.equals(TAG_GRANT)) {
-                pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                if (DEBUG_BACKUP) {
-                    Slog.v(TAG, "+++ Restoring grants for package " + pkgName);
-                }
-            } else if (tagName.equals(TAG_PERMISSION)) {
-
-                final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED));
-                final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
-
-                int newFlagSet = 0;
-                if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
-                    newFlagSet |= FLAG_PERMISSION_USER_SET;
-                }
-                if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
-                    newFlagSet |= FLAG_PERMISSION_USER_FIXED;
-                }
-                if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
-                    newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-                }
-                if (DEBUG_BACKUP) {
-                    Slog.v(TAG, "  + Restoring grant:"
-                            + " pkg=" + pkgName
-                            + " perm=" + permName
-                            + " granted=" + isGranted
-                            + " bits=0x" + Integer.toHexString(newFlagSet));
-                }
-                final PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (ps != null) {
-                    // Already installed so we apply the grant immediately
-                    if (DEBUG_BACKUP) {
-                        Slog.v(TAG, "        + already installed; applying");
-                    }
-                    PermissionsState perms = ps.getPermissionsState();
-                    BasePermission bp =
-                            (BasePermission) mPermissionManager.getPermissionTEMP(permName);
-                    if (bp != null) {
-                        if (isGranted) {
-                            perms.grantRuntimePermission(bp, userId);
-                        }
-                        if (newFlagSet != 0) {
-                            perms.updatePermissionFlags(
-                                    bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
-                        }
-                    }
-                } else {
-                    // Need to wait for post-restore install to apply the grant
-                    if (DEBUG_BACKUP) {
-                        Slog.v(TAG, "        - not yet installed; saving for later");
-                    }
-                    mSettings.processRestoredPermissionGrantLPr(pkgName, permName,
-                            isGranted, newFlagSet, userId);
-                }
-            } else {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName);
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-
-        scheduleWriteSettingsLocked();
-        mSettings.writeRuntimePermissionsForUserLPr(userId, false);
-    }
-
-    @Override
     public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
             int sourceUserId, int targetUserId, int flags) {
         mContext.enforceCallingOrSelfPermission(
@@ -21285,10 +21148,6 @@
                 }
             }
 
-            if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
-                mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
-            }
-
             if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
                 // XXX should handle packageName != null by dumping only install data that
                 // the given package is involved with.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 975ffb2..92fe377 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -19,10 +19,6 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
@@ -249,23 +245,6 @@
     private static final String ATTR_SDK_VERSION = "sdkVersion";
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
 
-    // Bookkeeping for restored permission grants
-    private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
-    // package name: ATTR_PACKAGE_NAME
-    private static final String TAG_PERMISSION_ENTRY = "perm";
-    // permission name: ATTR_NAME
-    // permission granted (boolean): ATTR_GRANTED
-    private static final String ATTR_USER_SET = "set";
-    private static final String ATTR_USER_FIXED = "fixed";
-    private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
-    private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
-
-    // Flag mask of restored permission grants that are applied at install time
-    private static final int USER_RUNTIME_GRANT_MASK =
-            FLAG_PERMISSION_USER_SET
-            | FLAG_PERMISSION_USER_FIXED
-            | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-
     private final Object mLock;
 
     private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
@@ -303,26 +282,6 @@
         int[] excludedUserIds;
     }
 
-    // Bookkeeping for restored user permission grants
-    final class RestoredPermissionGrant {
-        String permissionName;
-        boolean granted;
-        int grantBits;
-
-        RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) {
-            permissionName = name;
-            granted = isGranted;
-            grantBits = theGrantBits;
-        }
-    }
-
-    // This would be more compact as a flat array of restored grants or something, but we
-    // may have quite a few, especially during early device lifetime, and avoiding all those
-    // linear lookups will be important.
-    private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>
-            mRestoredUserGrants =
-                new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>();
-
     private static int mFirstAvailableUid = 0;
 
     /** Map from volume UUID to {@link VersionInfo} */
@@ -461,43 +420,6 @@
         return mRenamedPackages.put(pkgName, origPkgName);
     }
 
-    void applyPendingPermissionGrantsLPw(String packageName, int userId) {
-        ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
-                mRestoredUserGrants.get(userId);
-        if (grantsByPackage == null || grantsByPackage.size() == 0) {
-            return;
-        }
-
-        ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName);
-        if (grants == null || grants.size() == 0) {
-            return;
-        }
-
-        final PackageSetting ps = mPackages.get(packageName);
-        if (ps == null) {
-            Slog.e(TAG, "Can't find supposedly installed package " + packageName);
-            return;
-        }
-        final PermissionsState perms = ps.getPermissionsState();
-
-        for (RestoredPermissionGrant grant : grants) {
-            BasePermission bp = mPermissions.getPermission(grant.permissionName);
-            if (bp != null) {
-                if (grant.granted) {
-                    perms.grantRuntimePermission(bp, userId);
-                }
-                perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits);
-            }
-        }
-
-        // And remove it from the pending-grant bookkeeping
-        grantsByPackage.remove(packageName);
-        if (grantsByPackage.size() < 1) {
-            mRestoredUserGrants.remove(userId);
-        }
-        writeRuntimePermissionsForUserLPr(userId, false);
-    }
-
     public boolean canPropagatePermissionToInstantApp(String permName) {
         return mPermissions.canPropagatePermissionToInstantApp(permName);
     }
@@ -1982,13 +1904,6 @@
         }
     }
 
-    // Specifically for backup/restore
-    public void processRestoredPermissionGrantLPr(String pkgName, String permission,
-            boolean isGranted, int restoredFlagSet, int userId) {
-        mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
-                pkgName, permission, isGranted, restoredFlagSet, userId);
-    }
-
     void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
             throws IllegalArgumentException, IllegalStateException, IOException {
         serializer.startTag(null, TAG_DEFAULT_APPS);
@@ -5014,51 +4929,6 @@
         pw.print(mReadMessages.toString());
     }
 
-    void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) {
-        if (mRestoredUserGrants.size() > 0) {
-            pw.println();
-            pw.println("Restored (pending) permission grants:");
-            for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) {
-                ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
-                        mRestoredUserGrants.valueAt(userIndex);
-                if (grantsByPackage != null && grantsByPackage.size() > 0) {
-                    final int userId = mRestoredUserGrants.keyAt(userIndex);
-                    pw.print("  User "); pw.println(userId);
-
-                    for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) {
-                        ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex);
-                        if (grants != null && grants.size() > 0) {
-                            final String pkgName = grantsByPackage.keyAt(pkgIndex);
-                            pw.print("    "); pw.print(pkgName); pw.println(" :");
-
-                            for (RestoredPermissionGrant g : grants) {
-                                pw.print("      ");
-                                pw.print(g.permissionName);
-                                if (g.granted) {
-                                    pw.print(" GRANTED");
-                                }
-                                if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
-                                    pw.print(" user_set");
-                                }
-                                if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
-                                    pw.print(" user_fixed");
-                                }
-                                if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
-                                    pw.print(" revoke_on_upgrade");
-                                }
-                                if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
-                                    pw.print(" revoke_when_requested");
-                                }
-                                pw.println();
-                            }
-                        }
-                    }
-                }
-            }
-            pw.println();
-        }
-    }
-
     private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
         if (pkg == null) {
             pw.print("unknown");
@@ -5328,55 +5198,6 @@
 
                 serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
 
-                // Now any restored permission grants that are waiting for the apps
-                // in question to be installed.  These are stored as per-package
-                // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
-                // number of individual permission grant entities.
-                if (mRestoredUserGrants.get(userId) != null) {
-                    ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
-                            mRestoredUserGrants.get(userId);
-                    if (restoredGrants != null) {
-                        final int pkgCount = restoredGrants.size();
-                        for (int i = 0; i < pkgCount; i++) {
-                            final ArraySet<RestoredPermissionGrant> pkgGrants =
-                                    restoredGrants.valueAt(i);
-                            if (pkgGrants != null && pkgGrants.size() > 0) {
-                                final String pkgName = restoredGrants.keyAt(i);
-                                serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
-                                serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
-
-                                final int N = pkgGrants.size();
-                                for (int z = 0; z < N; z++) {
-                                    RestoredPermissionGrant g = pkgGrants.valueAt(z);
-                                    serializer.startTag(null, TAG_PERMISSION_ENTRY);
-                                    serializer.attribute(null, ATTR_NAME, g.permissionName);
-
-                                    if (g.granted) {
-                                        serializer.attribute(null, ATTR_GRANTED, "true");
-                                    }
-
-                                    if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
-                                        serializer.attribute(null, ATTR_USER_SET, "true");
-                                    }
-                                    if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
-                                        serializer.attribute(null, ATTR_USER_FIXED, "true");
-                                    }
-                                    if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
-                                        serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
-                                    }
-                                    if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
-                                            != 0) {
-                                        serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
-                                                "true");
-                                    }
-                                    serializer.endTag(null, TAG_PERMISSION_ENTRY);
-                                }
-                                serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
-                            }
-                        }
-                    }
-                }
-
                 serializer.endDocument();
                 destination.finishWrite(out);
 
@@ -5455,29 +5276,6 @@
             }
         }
 
-        // Backup/restore support
-
-        public void rememberRestoredUserGrantLPr(String pkgName, String permission,
-                boolean isGranted, int restoredFlagSet, int userId) {
-            // This change will be remembered at write-settings time
-            ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
-                    mRestoredUserGrants.get(userId);
-            if (grantsByPackage == null) {
-                grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>();
-                mRestoredUserGrants.put(userId, grantsByPackage);
-            }
-
-            ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName);
-            if (grants == null) {
-                grants = new ArraySet<RestoredPermissionGrant>();
-                grantsByPackage.put(pkgName, grants);
-            }
-
-            RestoredPermissionGrant grant = new RestoredPermissionGrant(permission,
-                    isGranted, restoredFlagSet);
-            grants.add(grant);
-        }
-
         // Private internals
 
         @GuardedBy("Settings.this.mLock")
@@ -5520,50 +5318,6 @@
                         }
                         parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
                     } break;
-
-                    case TAG_RESTORED_RUNTIME_PERMISSIONS: {
-                        final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                        parseRestoredRuntimePermissionsLPr(parser, pkgName, userId);
-                    } break;
-                }
-            }
-        }
-
-        private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser,
-                final String pkgName, final int userId) throws IOException, XmlPullParserException {
-            final int outerDepth = parser.getDepth();
-            int type;
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                switch (parser.getName()) {
-                    case TAG_PERMISSION_ENTRY: {
-                        final String permName = parser.getAttributeValue(null, ATTR_NAME);
-                        final boolean isGranted = "true".equals(
-                                parser.getAttributeValue(null, ATTR_GRANTED));
-
-                        int permBits = 0;
-                        if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
-                            permBits |= FLAG_PERMISSION_USER_SET;
-                        }
-                        if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
-                            permBits |= FLAG_PERMISSION_USER_FIXED;
-                        }
-                        if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
-                            permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-                        }
-                        if ("true".equals(parser.getAttributeValue(null,
-                                ATTR_REVOKE_WHEN_REQUESTED))) {
-                            permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
-                        }
-
-                        if (isGranted || permBits != 0) {
-                            rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
-                        }
-                    } break;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 38940d6..f56b984 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -30,6 +30,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
@@ -43,6 +44,9 @@
 import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -69,7 +73,9 @@
 import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
+import android.permission.PermissionManagerInternal;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -77,6 +83,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -91,9 +98,8 @@
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy
-        .DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState.PermissionState;
 
 import libcore.util.EmptyArray;
@@ -106,6 +112,10 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Manages all permissions and handles permissions related tasks.
@@ -122,6 +132,8 @@
     /** Permission grant: grant as runtime a permission that was granted as an install time one. */
     private static final int GRANT_UPGRADE = 4;
 
+    private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
+
     /** Cap the size of permission trees that 3rd party apps can define; in characters of text */
     private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;
     /** Empty array to avoid allocations */
@@ -146,6 +158,9 @@
     /** Internal connection to the user manager */
     private final UserManagerInternal mUserManagerInt;
 
+    /** Permission controller: User space permission management */
+    private PermissionControllerManager mPermissionControllerManager;
+
     /** Default permission policy to provide proper behaviour out-of-the-box */
     private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
 
@@ -180,6 +195,16 @@
     @GuardedBy("mLock")
     private ArrayMap<String, List<String>> mBackgroundPermissions;
 
+    /**
+     * A permission backup might contain apps that are not installed. In this case we delay the
+     * restoration until the app is installed.
+     *
+     * <p>This array ({@code userId -> noDelayedBackupLeft}) is {@code true} for all the users where
+     * there is <u>no more</u> delayed backup left.
+     */
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mHasNoDelayedPermBackup = new SparseBooleanArray();
+
     PermissionManagerService(Context context,
             @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
             @NonNull Object externalLock) {
@@ -218,29 +243,31 @@
             }
         }
 
-        LocalServices.addService(
-                PermissionManagerInternal.class, new PermissionManagerInternalImpl());
+        PermissionManagerServiceInternalImpl localService =
+                new PermissionManagerServiceInternalImpl();
+        LocalServices.addService(PermissionManagerServiceInternal.class, localService);
+        LocalServices.addService(PermissionManagerInternal.class, localService);
     }
 
     /**
      * Creates and returns an initialized, internal service for use by other components.
      * <p>
      * The object returned is identical to the one returned by the LocalServices class using:
-     * {@code LocalServices.getService(PermissionManagerInternal.class);}
+     * {@code LocalServices.getService(PermissionManagerServiceInternal.class);}
      * <p>
      * NOTE: The external lock is temporary and should be removed. This needs to be a
      * lock created by the permission manager itself.
      */
-    public static PermissionManagerInternal create(Context context,
+    public static PermissionManagerServiceInternal create(Context context,
             @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
             @NonNull Object externalLock) {
-        final PermissionManagerInternal permMgrInt =
-                LocalServices.getService(PermissionManagerInternal.class);
+        final PermissionManagerServiceInternal permMgrInt =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
         if (permMgrInt != null) {
             return permMgrInt;
         }
         new PermissionManagerService(context, defaultGrantCallback, externalLock);
-        return LocalServices.getService(PermissionManagerInternal.class);
+        return LocalServices.getService(PermissionManagerServiceInternal.class);
     }
 
     @Nullable BasePermission getPermission(String permName) {
@@ -332,6 +359,74 @@
     }
 
     /**
+     * Get the state of the runtime permissions as xml file.
+     *
+     * <p>Can not be called on main thread.
+     *
+     * @param user The user the data should be extracted for
+     *
+     * @return The state as a xml file
+     */
+    private @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+        CompletableFuture<byte[]> backup = new CompletableFuture<>();
+        mPermissionControllerManager.getRuntimePermissionBackup(user, mContext.getMainExecutor(),
+                backup::complete);
+
+        try {
+            return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException  | TimeoutException e) {
+            Slog.e(TAG, "Cannot create permission backup for " + user, e);
+            return null;
+        }
+    }
+
+    /**
+     * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+     *
+     * <p>If not all state can be restored, the un-appliable state will be delayed and can be
+     * applied via {@link #restoreDelayedRuntimePermissions}.
+     *
+     * @param backup The state as an xml file
+     * @param user The user the data should be restored for
+     */
+    private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+        synchronized (mLock) {
+            mHasNoDelayedPermBackup.delete(user.getIdentifier());
+            mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user);
+        }
+    }
+
+    /**
+     * Try to apply permission backup that was previously not applied.
+     *
+     * <p>Can not be called on main thread.
+     *
+     * @param packageName The package that is newly installed
+     * @param user The user the package is installed for
+     *
+     * @see #restoreRuntimePermissions
+     */
+    private void restoreDelayedRuntimePermissions(@NonNull String packageName,
+            @NonNull UserHandle user) {
+        synchronized (mLock) {
+            if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) {
+                return;
+            }
+
+            mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user,
+                    mContext.getMainExecutor(), (hasMoreBackup) -> {
+                        if (hasMoreBackup) {
+                            return;
+                        }
+
+                        synchronized (mLock) {
+                            mHasNoDelayedPermBackup.put(user.getIdentifier(), true);
+                        }
+                    });
+        }
+    }
+
+    /**
      * Returns {@code true} if the permission can be implied from another granted permission.
      * <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions,
      * such as ACCESS_COURSE_LOCATION. If the caller holds an umbrella permission, give
@@ -741,7 +836,6 @@
         if (ps == null) {
             return;
         }
-        final boolean isLegacySystemApp = mPackageManagerInt.isLegacySystemApp(pkg);
 
         final PermissionsState permissionsState = ps.getPermissionsState();
         PermissionsState origPermissions = permissionsState;
@@ -828,17 +922,9 @@
                     // For all apps normal permissions are install time ones.
                     grant = GRANT_INSTALL;
                 } else if (bp.isRuntime()) {
-                    // If a permission review is required for legacy apps we represent
-                    // their permissions as always granted runtime ones since we need
-                    // to keep the review required permission flag per user while an
-                    // install permission's state is shared across all users.
                     if (origPermissions.hasInstallPermission(bp.getName())) {
-                        // For legacy apps that became modern, install becomes runtime.
-                        grant = GRANT_UPGRADE;
-                    } else if (isLegacySystemApp) {
-                        // For legacy system apps, install becomes runtime.
-                        // We cannot check hasInstallPermission() for system apps since those
-                        // permissions were granted implicitly and not persisted pre-M.
+                        // Before Q we represented some runtime permissions as install permissions,
+                        // in Q we cannot do this anymore. Hence upgrade them all.
                         grant = GRANT_UPGRADE;
                     } else {
                         // For modern apps keep runtime permissions unchanged.
@@ -891,110 +977,111 @@
                             }
                             // Grant an install permission.
                             if (permissionsState.grantInstallPermission(bp) !=
-                                    PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                                    PERMISSION_OPERATION_FAILURE) {
                                 changedInstallPermission = true;
                             }
                         } break;
 
                         case GRANT_RUNTIME: {
-                            // Grant previously granted runtime permissions.
-                            for (int userId : UserManagerService.getInstance().getUserIds()) {
-                                final PermissionState permissionState = origPermissions
+                            for (int userId : currentUserIds) {
+                                PermissionState permState = origPermissions
                                         .getRuntimePermissionState(perm, userId);
-                                int flags = permissionState != null
-                                        ? permissionState.getFlags() : 0;
-                                if (origPermissions.hasRuntimePermission(perm, userId)) {
-                                    // Don't propagate the permission in a permission review
-                                    // mode if the former was revoked, i.e. marked to not
-                                    // propagate on upgrade. Note that in a permission review
-                                    // mode install permissions are represented as constantly
-                                    // granted runtime ones since we need to keep a per user
-                                    // state associated with the permission. Also the revoke
-                                    // on upgrade flag is no longer applicable and is reset.
-                                    final boolean revokeOnUpgrade = (flags & PackageManager
-                                            .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
-                                    if (revokeOnUpgrade) {
-                                        flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-                                        // Since we changed the flags, we have to write.
-                                        updatedUserIds = ArrayUtils.appendInt(
-                                                updatedUserIds, userId);
+                                int flags = permState != null ? permState.getFlags() : 0;
+
+                                boolean wasChanged = false;
+
+                                if (appSupportsRuntimePermissions) {
+                                    // Remove review flag as it is not necessary anymore
+                                    if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+                                        flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+                                        wasChanged = true;
                                     }
-                                    if (!revokeOnUpgrade) {
-                                        if (permissionsState.grantRuntimePermission(bp, userId) ==
-                                                PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                                            // If we cannot put the permission as it was,
-                                            // we have to write.
-                                            updatedUserIds = ArrayUtils.appendInt(
-                                                    updatedUserIds, userId);
+
+                                    if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+                                        flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+                                        wasChanged = true;
+                                    } else {
+                                        if (permState != null && permState.isGranted()) {
+                                            if (permissionsState.grantRuntimePermission(bp, userId)
+                                                    == PERMISSION_OPERATION_FAILURE) {
+                                                wasChanged = true;
+                                            }
+                                        }
+                                    }
+                                } else {
+                                    if (permState == null) {
+                                        // New permission
+                                        if (PLATFORM_PACKAGE_NAME.equals(
+                                                bp.getSourcePackageName())) {
+                                            if (!bp.isRemoved()) {
+                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED
+                                                        | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+                                                wasChanged = true;
+                                            }
                                         }
                                     }
 
-                                    // If the app supports runtime permissions no need for a review.
-                                    if (appSupportsRuntimePermissions
-                                            && (flags & PackageManager
-                                                    .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                                        flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
-                                        // Since we changed the flags, we have to write.
-                                        updatedUserIds = ArrayUtils.appendInt(
-                                                updatedUserIds, userId);
-                                    }
-                                } else if (!appSupportsRuntimePermissions) {
-                                    // For legacy apps that need a permission review, every new
-                                    // runtime permission is granted but it is pending a review.
-                                    // We also need to review only platform defined runtime
-                                    // permissions as these are the only ones the platform knows
-                                    // how to disable the API to simulate revocation as legacy
-                                    // apps don't expect to run with revoked permissions.
-                                    if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
-                                        if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
-                                                && !bp.isRemoved()) {
-                                            flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
-                                            // We changed the flags, hence have to write.
-                                            updatedUserIds = ArrayUtils.appendInt(
-                                                    updatedUserIds, userId);
-                                        }
-                                    }
                                     if (permissionsState.grantRuntimePermission(bp, userId)
-                                            != PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                                        // We changed the permission, hence have to write.
-                                        updatedUserIds = ArrayUtils.appendInt(
-                                                updatedUserIds, userId);
+                                            != PERMISSION_OPERATION_FAILURE) {
+                                        wasChanged = true;
                                     }
                                 }
-                                // Propagate the permission flags.
+
+                                if (wasChanged) {
+                                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+                                }
+
                                 permissionsState.updatePermissionFlags(bp, userId, flags, flags);
                             }
                         } break;
 
                         case GRANT_UPGRADE: {
-                            // Grant runtime permissions for a previously held install permission.
-                            final PermissionState permissionState = origPermissions
+                            // Upgrade from Pre-Q to Q permission model. Make all permissions
+                            // runtime
+                            PermissionState permState = origPermissions
                                     .getInstallPermissionState(perm);
-                            final int flags =
-                                    (permissionState != null) ? permissionState.getFlags() : 0;
+                            int flags = (permState != null) ? permState.getFlags() : 0;
 
+                            // Remove install permission
                             if (origPermissions.revokeInstallPermission(bp)
-                                    != PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                                // We will be transferring the permission flags, so clear them.
+                                    != PERMISSION_OPERATION_FAILURE) {
                                 origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
                                         PackageManager.MASK_PERMISSION_FLAGS, 0);
                                 changedInstallPermission = true;
                             }
 
-                            // If the permission is not to be promoted to runtime we ignore it and
-                            // also its other flags as they are not applicable to install permissions.
-                            if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
-                                for (int userId : currentUserIds) {
+                            for (int userId : currentUserIds) {
+                                boolean wasChanged = false;
+
+                                if (appSupportsRuntimePermissions) {
+                                    // Remove review flag as it is not necessary anymore
+                                    if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+                                        flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+                                        wasChanged = true;
+                                    }
+
+                                    if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+                                        flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+                                        wasChanged = true;
+                                    } else {
+                                        if (permissionsState.grantRuntimePermission(bp, userId) !=
+                                                PERMISSION_OPERATION_FAILURE) {
+                                             wasChanged = true;
+                                        }
+                                    }
+                                } else {
                                     if (permissionsState.grantRuntimePermission(bp, userId) !=
-                                            PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                                        // Transfer the permission flags.
-                                        permissionsState.updatePermissionFlags(bp, userId,
-                                                flags, flags);
-                                        // If we granted the permission, we have to write.
-                                        updatedUserIds = ArrayUtils.appendInt(
-                                                updatedUserIds, userId);
+                                            PERMISSION_OPERATION_FAILURE) {
+                                        flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                        wasChanged = true;
                                     }
                                 }
+
+                                if (wasChanged) {
+                                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+                                }
+
+                                permissionsState.updatePermissionFlags(bp, userId, flags, flags);
                             }
                         } break;
 
@@ -1011,7 +1098,7 @@
                     }
                 } else {
                     if (permissionsState.revokeInstallPermission(bp) !=
-                            PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                            PERMISSION_OPERATION_FAILURE) {
                         // Also drop the permission flags.
                         permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
                                 PackageManager.MASK_PERMISSION_FLAGS, 0);
@@ -1094,6 +1181,10 @@
             @NonNull int[] updatedUserIds) {
         AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
 
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+            return updatedUserIds;
+        }
+
         String pkgName = pkg.packageName;
 
         int[] users = UserManagerService.getInstance().getUserIds();
@@ -1119,26 +1210,14 @@
                             if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
                                     | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
                                     == 0) {
-                                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
-                                    if (permissionToOpCode(permission) != OP_NONE) {
-                                        setAppOpMode(permission, pkg, userId, MODE_IGNORED);
+                                int revokeResult = ps.revokeRuntimePermission(bp, userId);
+                                if (revokeResult
+                                        != PERMISSION_OPERATION_FAILURE) {
 
-                                        if (DEBUG_PERMISSIONS) {
-                                            Slog.i(TAG, "Revoking app-op "
-                                                    + permissionToOp(permission) + " for " + pkgName
-                                                    + " as it is now requested");
-                                        }
-                                    }
-                                } else {
-                                    int revokeResult = ps.revokeRuntimePermission(bp, userId);
-                                    if (revokeResult
-                                            != PermissionsState.PERMISSION_OPERATION_FAILURE) {
-
-                                        if (DEBUG_PERMISSIONS) {
-                                            Slog.i(TAG, "Revoking runtime permission " + permission
-                                                    + " for " + pkgName
-                                                    + " as it is now requested");
-                                        }
+                                    if (DEBUG_PERMISSIONS) {
+                                        Slog.i(TAG, "Revoking runtime permission " + permission
+                                                + " for " + pkgName
+                                                + " as it is now requested");
                                     }
                                 }
 
@@ -1925,7 +2004,7 @@
             // Development permissions must be handled specially, since they are not
             // normal runtime permissions.  For now they apply to all users.
             if (permissionsState.grantInstallPermission(bp) !=
-                    PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                    PERMISSION_OPERATION_FAILURE) {
                 if (callback != null) {
                     callback.onInstallPermissionGranted();
                 }
@@ -1945,7 +2024,7 @@
 
         final int result = permissionsState.grantRuntimePermission(bp, userId);
         switch (result) {
-            case PermissionsState.PERMISSION_OPERATION_FAILURE: {
+            case PERMISSION_OPERATION_FAILURE: {
                 return;
             }
 
@@ -2045,7 +2124,7 @@
             // Development permissions must be handled specially, since they are not
             // normal runtime permissions.  For now they apply to all users.
             if (permissionsState.revokeInstallPermission(bp) !=
-                    PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                    PERMISSION_OPERATION_FAILURE) {
                 if (callback != null) {
                     callback.onInstallPermissionRevoked();
                 }
@@ -2054,7 +2133,7 @@
         }
 
         if (permissionsState.revokeRuntimePermission(bp, userId) ==
-                PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                PERMISSION_OPERATION_FAILURE) {
             return;
         }
 
@@ -2522,6 +2601,8 @@
             throw new IllegalStateException("Signature|privileged permissions not in "
                     + "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
         }
+
+        mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
     }
 
     private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
@@ -2574,7 +2655,7 @@
         return mBackgroundPermissions;
     }
 
-    private class PermissionManagerInternalImpl extends PermissionManagerInternal {
+    private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
         @Override
         public void systemReady() {
             PermissionManagerService.this.systemReady();
@@ -2737,5 +2818,21 @@
                 return mSettings.getPermissionLocked(permName);
             }
         }
+
+        @Override
+        public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+            return PermissionManagerService.this.backupRuntimePermissions(user);
+        }
+
+        @Override
+        public void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+            PermissionManagerService.this.restoreRuntimePermissions(backup, user);
+        }
+
+        @Override
+        public void restoreDelayedRuntimePermissions(@NonNull String packageName,
+                @NonNull UserHandle user) {
+            PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
similarity index 96%
rename from services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
rename to services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f4979746..1dd2408 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,19 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.PackageManager.PermissionInfoFlags;
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
-import android.content.pm.PackageManager.PermissionInfoFlags;
+import android.permission.PermissionManagerInternal;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
 /**
- * Internal interfaces to be used by other components within the system server.
+ * Internal interfaces services.
+ *
+ * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
  */
-public abstract class PermissionManagerInternal {
+public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
     /**
      * Callbacks invoked when interesting actions have been taken on a permission.
      * <p>
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 0892b32..2280d3f 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -16,6 +16,9 @@
                 },
                 {
                     "include-filter": "android.permission.cts.SplitPermissionTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.PermissionFlagsTest"
                 }
             ]
         },
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index edca2e3..4815e5c 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -85,7 +85,9 @@
 import android.os.Temperature;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -1956,6 +1958,27 @@
         pulledData.add(e);
     }
 
+    private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        StorageManager storageManager = mContext.getSystemService(StorageManager.class);
+        if (storageManager != null) {
+            List<VolumeInfo> volumes = storageManager.getVolumes();
+            for (VolumeInfo vol : volumes) {
+                final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
+                final DiskInfo diskInfo = vol.getDisk();
+                if (diskInfo != null && diskInfo.isSd()) {
+                    if (envState.equals(Environment.MEDIA_MOUNTED)) {
+                        StatsLogEventWrapper e =
+                                new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+                        e.writeInt(vol.getType() + 1);
+                        e.writeLong(diskInfo.size);
+                        pulledData.add(e);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Pulls various data.
      */
@@ -2148,6 +2171,10 @@
                 pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.SDCARD_INFO: {
+                pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 7a3f030..f581bc0 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -44,7 +44,7 @@
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 /**
  * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -133,7 +133,7 @@
     }
 
     private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
-        return LocalServices.getService(PermissionManagerInternal.class)
+        return LocalServices.getService(PermissionManagerServiceInternal.class)
                 .getDefaultPermissionGrantPolicy();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 168c9ad..899bf7c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5090,11 +5090,7 @@
 
     @Override
     public void startWindowTrace(){
-        try {
-            mWindowTracing.startTrace(null /* printwriter */);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+        mWindowTracing.startTrace(null /* printwriter */);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index e4461ea..2ce6e6c 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -20,7 +20,6 @@
 import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
 import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
 
-import android.os.Trace;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -36,24 +35,30 @@
 /**
  * Buffer used for window tracing.
  */
-abstract class WindowTraceBuffer {
+class WindowTraceBuffer {
     private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
 
-    final Object mBufferLock = new Object();
-    final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
-    final File mTraceFile;
-    int mBufferSize;
-    private final int mBufferCapacity;
+    private final Object mBufferLock = new Object();
 
-    WindowTraceBuffer(int size, File traceFile) throws IOException {
-        mBufferCapacity = size;
-        mTraceFile = traceFile;
+    private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
+    private int mBufferUsedSize;
+    private int mBufferCapacity;
 
-        initTraceFile();
+    WindowTraceBuffer(int bufferCapacity) {
+        mBufferCapacity = bufferCapacity;
+        resetBuffer();
     }
 
     int getAvailableSpace() {
-        return mBufferCapacity - mBufferSize;
+        return mBufferCapacity - mBufferUsedSize;
+    }
+
+    int size() {
+        return mBuffer.size();
+    }
+
+    void setCapacity(int capacity) {
+        mBufferCapacity = capacity;
     }
 
     /**
@@ -70,42 +75,37 @@
                     + mBufferCapacity + " Object size: " + protoLength);
         }
         synchronized (mBufferLock) {
-            boolean canAdd = canAdd(protoLength);
-            if (canAdd) {
-                mBuffer.add(proto);
-                mBufferSize += protoLength;
-            }
+            discardOldest(protoLength);
+            mBuffer.add(proto);
+            mBufferUsedSize += protoLength;
             mBufferLock.notify();
         }
     }
 
-    /**
-     * Stops the buffer execution and flush all buffer content to the disk.
-     *
-     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
-     */
-    void dump() throws IOException, InterruptedException {
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile");
-            writeTraceToFile();
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-        }
-    }
-
-    @VisibleForTesting
     boolean contains(byte[] other) {
         return mBuffer.stream()
                 .anyMatch(p -> Arrays.equals(p.getBytes(), other));
     }
 
-    private void initTraceFile() throws IOException {
-        mTraceFile.delete();
-        try (OutputStream os = new FileOutputStream(mTraceFile)) {
-            mTraceFile.setReadable(true, false);
-            ProtoOutputStream proto = new ProtoOutputStream(os);
-            proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
-            proto.flush();
+    /**
+     * Writes the trace buffer to disk.
+     */
+    void writeTraceToFile(File traceFile) throws IOException {
+        synchronized (mBufferLock) {
+            traceFile.delete();
+            traceFile.setReadable(true, false);
+            try (OutputStream os = new FileOutputStream(traceFile)) {
+                ProtoOutputStream proto = new ProtoOutputStream();
+                proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+                os.write(proto.getBytes());
+                while (!mBuffer.isEmpty()) {
+                    proto = mBuffer.poll();
+                    mBufferUsedSize -= proto.getRawSize();
+                    byte[] protoBytes = proto.getBytes();
+                    os.write(protoBytes);
+                }
+                os.flush();
+            }
         }
     }
 
@@ -114,59 +114,48 @@
      * smaller than the overall buffer size.
      *
      * @param protoLength byte array representation of the Proto object to add
-     * @return {@code true} if the element can be added to the buffer or not
      */
-    abstract boolean canAdd(int protoLength);
+    private void discardOldest(int protoLength) {
+        long availableSpace = getAvailableSpace();
+
+        while (availableSpace < protoLength) {
+
+            ProtoOutputStream item = mBuffer.poll();
+            if (item == null) {
+                throw new IllegalStateException("No element to discard from buffer");
+            }
+            mBufferUsedSize -= item.getRawSize();
+            availableSpace = getAvailableSpace();
+        }
+    }
 
     /**
-     * Flush all buffer content to the disk.
-     *
-     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
+     * Removes all elements form the buffer
      */
-    abstract void writeTraceToFile() throws IOException, InterruptedException;
-
-    /**
-     * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceRingBuffer} for
-     * continuous mode or a {@link WindowTraceQueueBuffer} otherwise
-     */
-    static class Builder {
-        private boolean mContinuous;
-        private File mTraceFile;
-        private int mBufferCapacity;
-
-        Builder setContinuousMode(boolean continuous) {
-            mContinuous = continuous;
-            return this;
+    void resetBuffer() {
+        synchronized (mBufferLock) {
+            mBuffer.clear();
+            mBufferUsedSize = 0;
         }
+    }
 
-        Builder setTraceFile(File traceFile) {
-            mTraceFile = traceFile;
-            return this;
-        }
+    @VisibleForTesting
+    int getBufferSize() {
+        return mBufferUsedSize;
+    }
 
-        Builder setBufferCapacity(int size) {
-            mBufferCapacity = size;
-            return this;
-        }
-
-        File getFile() {
-            return mTraceFile;
-        }
-
-        WindowTraceBuffer build() throws IOException {
-            if (mBufferCapacity <= 0) {
-                throw new IllegalStateException("Buffer capacity must be greater than 0.");
-            }
-
-            if (mTraceFile == null) {
-                throw new IllegalArgumentException("A valid trace file must be specified.");
-            }
-
-            if (mContinuous) {
-                return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile);
-            } else {
-                return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
-            }
+    String getStatus() {
+        synchronized (mBufferLock) {
+            return "Buffer size: "
+                    + mBufferCapacity
+                    + " bytes"
+                    + "\n"
+                    + "Buffer usage: "
+                    + mBufferUsedSize
+                    + " bytes"
+                    + "\n"
+                    + "Elements in the buffer: "
+                    + mBuffer.size();
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
deleted file mode 100644
index 5888b7a..0000000
--- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.os.Build.IS_USER;
-
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
- * {@code #size size} bytes of window trace elements.
- * Once the buffer is full it will no longer accepts new elements.
- */
-class WindowTraceQueueBuffer extends WindowTraceBuffer {
-    private static final String TAG = "WindowTracing";
-
-    private Thread mConsumerThread;
-    private boolean mCancel;
-
-    @VisibleForTesting
-    WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread)
-            throws IOException {
-        super(size, traceFile);
-        if (startConsumerThread) {
-            initializeConsumerThread();
-        }
-    }
-
-    WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
-        this(size, traceFile, !IS_USER);
-    }
-
-    private void initializeConsumerThread() {
-        mCancel = false;
-        mConsumerThread = new Thread(() -> {
-            try {
-                loop();
-            } catch (InterruptedException e) {
-                Log.i(TAG, "Interrupting trace consumer thread");
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to execute trace consumer thread", e);
-            }
-        }, "window_tracing");
-        mConsumerThread.start();
-    }
-
-    private void loop() throws IOException, InterruptedException {
-        while (!mCancel) {
-            ProtoOutputStream proto;
-            synchronized (mBufferLock) {
-                mBufferLock.wait();
-                proto = mBuffer.poll();
-                if (proto != null) {
-                    mBufferSize -= proto.getRawSize();
-                }
-            }
-            if (proto != null) {
-                try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
-                    byte[] protoBytes = proto.getBytes();
-                    os.write(protoBytes);
-                }
-            }
-        }
-    }
-
-    @Override
-    boolean canAdd(int protoLength) {
-        long availableSpace = getAvailableSpace();
-        return availableSpace >= protoLength;
-    }
-
-    @Override
-    void writeTraceToFile() throws InterruptedException {
-        synchronized (mBufferLock) {
-            mCancel = true;
-            mBufferLock.notify();
-        }
-        if (mConsumerThread != null) {
-            mConsumerThread.join();
-            mConsumerThread = null;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
deleted file mode 100644
index 77d30be..0000000
--- a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.util.proto.ProtoOutputStream;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A ring buffer to store the {@code #size size} bytes of window trace data.
- * The buffer operates on a trace entry level, that is, if the new trace data is larger than the
- * available buffer space, the buffer will discard as many full trace entries as necessary to fit
- * the new trace.
- */
-class WindowTraceRingBuffer extends WindowTraceBuffer {
-    WindowTraceRingBuffer(int size, File traceFile) throws IOException {
-        super(size, traceFile);
-    }
-
-    @Override
-    boolean canAdd(int protoLength) {
-        long availableSpace = getAvailableSpace();
-
-        while (availableSpace < protoLength) {
-            discardOldest();
-            availableSpace = getAvailableSpace();
-        }
-
-        return true;
-    }
-
-    @Override
-    void writeTraceToFile() throws IOException {
-        synchronized (mBufferLock) {
-            try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
-                while (!mBuffer.isEmpty()) {
-                    ProtoOutputStream proto = mBuffer.poll();
-                    mBufferSize -= proto.getRawSize();
-                    byte[] protoBytes = proto.getBytes();
-                    os.write(protoBytes);
-                }
-            }
-        }
-    }
-
-    private void discardOldest() {
-        ProtoOutputStream item = mBuffer.poll();
-        if (item == null) {
-            throw new IllegalStateException("No element to discard from buffer");
-        }
-        mBufferSize -= item.getRawSize();
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index abc474d..0ce215c 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -31,8 +31,6 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Choreographer;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -47,139 +45,191 @@
      * Maximum buffer size, currently defined as 512 KB
      * Size was experimentally defined to fit between 100 to 150 elements.
      */
-    private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
+    private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
+    private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
+    private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
+    private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
     private static final String TAG = "WindowTracing";
 
     private final WindowManagerService mService;
     private final Choreographer mChoreographer;
     private final WindowManagerGlobalLock mGlobalLock;
 
-    private final Object mLock = new Object();
-    private final WindowTraceBuffer.Builder mBufferBuilder;
+    private final Object mEnabledLock = new Object();
+    private final File mTraceFile;
+    private final WindowTraceBuffer mBuffer;
+    private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+            log("onFrame" /* where */);
 
-    private WindowTraceBuffer mTraceBuffer;
-
-    private @WindowTraceLogLevel int mWindowTraceLogLevel = WindowTraceLogLevel.TRIM;
-    private boolean mContinuousMode;
+    private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
+    private boolean mLogOnFrame = false;
     private boolean mEnabled;
     private volatile boolean mEnabledLockFree;
     private boolean mScheduled;
-    private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
-            log("onFrame" /* where */);
 
-    private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
-        this(file, service, choreographer, service.mGlobalLock);
+    static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+            Choreographer choreographer) {
+        File file = new File(TRACE_FILENAME);
+        return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM);
     }
 
-    @VisibleForTesting
-    WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
-            WindowManagerGlobalLock globalLock) {
-        mBufferBuilder = new WindowTraceBuffer.Builder()
-                .setTraceFile(file)
-                .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+    private WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+            int bufferCapacity) {
+        this(file, service, choreographer, service.mGlobalLock, bufferCapacity);
+    }
 
+    WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+            WindowManagerGlobalLock globalLock, int bufferCapacity) {
         mChoreographer = choreographer;
         mService = service;
         mGlobalLock = globalLock;
+        mTraceFile = file;
+        mBuffer = new WindowTraceBuffer(bufferCapacity);
+        setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
     }
 
-    void startTrace(@Nullable PrintWriter pw) throws IOException {
+    void startTrace(@Nullable PrintWriter pw) {
         if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
-        synchronized (mLock) {
-            logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
-            if (mTraceBuffer != null) {
-                writeTraceToFileLocked();
-            }
-            mTraceBuffer = mBufferBuilder
-                    .setContinuousMode(mContinuousMode)
-                    .build();
+        synchronized (mEnabledLock) {
+            logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+            mBuffer.resetBuffer();
             mEnabled = mEnabledLockFree = true;
         }
     }
 
-    private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
-        Log.i(TAG, msg);
-        if (pw != null) {
-            pw.println(msg);
-            pw.flush();
-        }
-    }
-
     void stopTrace(@Nullable PrintWriter pw) {
         if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
-        synchronized (mLock) {
-            logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
-                    + ". Waiting for traces to flush.");
+        synchronized (mEnabledLock) {
+            logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
             mEnabled = mEnabledLockFree = false;
 
-            synchronized (mLock) {
-                if (mEnabled) {
-                    logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
-                    throw new IllegalStateException("tracing enabled while waiting for flush.");
-                }
-                writeTraceToFileLocked();
-                mTraceBuffer = null;
+            if (mEnabled) {
+                logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+                throw new IllegalStateException("tracing enabled while waiting for flush.");
             }
-            logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
+            writeTraceToFileLocked();
+            logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
         }
     }
 
-    @VisibleForTesting
-    void setContinuousMode(boolean continuous, PrintWriter pw) {
-        logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
+    private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
+        logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
+        mLogLevel = logLevel;
 
-        if (mEnabled) {
-            logAndPrintln(pw, "Trace is currently active, change will take effect once the "
-                    + "trace is restarted.");
+        switch (logLevel) {
+            case WindowTraceLogLevel.ALL: {
+                setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
+                break;
+            }
+            case WindowTraceLogLevel.TRIM: {
+                setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
+                break;
+            }
+            case WindowTraceLogLevel.CRITICAL: {
+                setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
+                break;
+            }
         }
-        mContinuousMode = continuous;
-        mWindowTraceLogLevel = (continuous) ? WindowTraceLogLevel.CRITICAL :
-                WindowTraceLogLevel.TRIM;
+    }
+
+    private void setLogFrequency(boolean onFrame, PrintWriter pw) {
+        logAndPrintln(pw, "Setting window tracing log frequency to "
+                + ((onFrame) ? "frame" : "transaction"));
+        mLogOnFrame = onFrame;
+    }
+
+    private void setBufferCapacity(int capacity, PrintWriter pw) {
+        logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
+        mBuffer.setCapacity(capacity);
     }
 
     boolean isEnabled() {
         return mEnabledLockFree;
     }
 
-    static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
-            Choreographer choreographer) {
-        File file = new File("/data/misc/wmtrace/wm_trace.pb");
-        return new WindowTracing(file, service, choreographer);
-    }
-
     int onShellCommand(ShellCommand shell) {
         PrintWriter pw = shell.getOutPrintWriter();
-        try {
-            String cmd = shell.getNextArgRequired();
-            switch (cmd) {
-                case "start":
-                    startTrace(pw);
-                    return 0;
-                case "stop":
-                    stopTrace(pw);
-                    return 0;
-                case "continuous":
-                    setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw);
-                    return 0;
-                default:
-                    pw.println("Unknown command: " + cmd);
-                    return -1;
-            }
-        } catch (IOException e) {
-            logAndPrintln(pw, e.toString());
-            throw new RuntimeException(e);
+        String cmd = shell.getNextArgRequired();
+        switch (cmd) {
+            case "start":
+                startTrace(pw);
+                return 0;
+            case "stop":
+                stopTrace(pw);
+                return 0;
+            case "status":
+                logAndPrintln(pw, getStatus());
+                return 0;
+            case "frame":
+                setLogFrequency(true /* onFrame */, pw);
+                mBuffer.resetBuffer();
+                return 0;
+            case "transaction":
+                setLogFrequency(false /* onFrame */, pw);
+                mBuffer.resetBuffer();
+                return 0;
+            case "level":
+                String logLevelStr = shell.getNextArgRequired().toLowerCase();
+                switch (logLevelStr) {
+                    case "all": {
+                        setLogLevel(WindowTraceLogLevel.ALL, pw);
+                        break;
+                    }
+                    case "trim": {
+                        setLogLevel(WindowTraceLogLevel.TRIM, pw);
+                        break;
+                    }
+                    case "critical": {
+                        setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
+                        break;
+                    }
+                    default: {
+                        setLogLevel(WindowTraceLogLevel.TRIM, pw);
+                        break;
+                    }
+                }
+                mBuffer.resetBuffer();
+                return 0;
+            case "size":
+                setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
+                mBuffer.resetBuffer();
+                return 0;
+            default:
+                pw.println("Unknown command: " + cmd);
+                pw.println("Window manager trace options:");
+                pw.println("  start: Start logging");
+                pw.println("  stop: Stop logging");
+                pw.println("  frame: Log trace once per frame");
+                pw.println("  transaction: Log each transaction");
+                pw.println("  size: Set the maximum log size (in KB)");
+                pw.println("  level [lvl]: Set the log level between");
+                pw.println("    lvl may be one of:");
+                pw.println("      critical: Only visible windows with reduced information");
+                pw.println("      trim: All windows with reduced");
+                pw.println("      all: All window and information");
+                return -1;
         }
     }
 
+    private String getStatus() {
+        return "Status: "
+                + ((isEnabled()) ? "Enabled" : "Disabled")
+                + "\n"
+                + "Log level: "
+                + mLogLevel
+                + "\n"
+                + mBuffer.getStatus();
+    }
+
     /**
      * If tracing is enabled, log the current state or schedule the next frame to be logged,
-     * according to {@link #mContinuousMode}.
+     * according to {@link #mLogOnFrame}.
      *
      * @param where Logging point descriptor
      */
@@ -188,7 +238,7 @@
             return;
         }
 
-        if (mContinuousMode) {
+        if (mLogOnFrame) {
             schedule();
         } else {
             log(where);
@@ -215,25 +265,24 @@
     private void log(String where) {
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
         try {
-            synchronized (mGlobalLock) {
-                ProtoOutputStream os = new ProtoOutputStream();
-                long tokenOuter = os.start(ENTRY);
-                os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
-                os.write(WHERE, where);
+            ProtoOutputStream os = new ProtoOutputStream();
+            long tokenOuter = os.start(ENTRY);
+            os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+            os.write(WHERE, where);
 
+            long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+            synchronized (mGlobalLock) {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
                 try {
-                    long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
-                    mService.writeToProtoLocked(os, mWindowTraceLogLevel);
-                    os.end(tokenInner);
+                    mService.writeToProtoLocked(os, mLogLevel);
                 } finally {
                     Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                 }
-                os.end(tokenOuter);
-                mTraceBuffer.add(os);
-
-                mScheduled = false;
             }
+            os.end(tokenInner);
+            os.end(tokenOuter);
+            mBuffer.add(os);
+            mScheduled = false;
         } catch (Exception e) {
             Log.wtf(TAG, "Exception while tracing state", e);
         } finally {
@@ -242,31 +291,37 @@
     }
 
     /**
-     * Writes the trace buffer to disk. This method has no internal synchronization and should be
-     * externally synchronized
-     */
-    private void writeTraceToFileLocked() {
-        if (mTraceBuffer == null) {
-            return;
-        }
-
-        try {
-            mTraceBuffer.dump();
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to write buffer to file", e);
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
-        }
-    }
-
-    /**
-     * Writes the trace buffer to disk and clones it into a new file for the bugreport.
+     * Writes the trace buffer to new file for the bugreport.
+     *
      * This method is synchronized with {@code #startTrace(PrintWriter)} and
      * {@link #stopTrace(PrintWriter)}.
      */
     void writeTraceToFile() {
-        synchronized (mLock) {
+        synchronized (mEnabledLock) {
             writeTraceToFileLocked();
         }
     }
-}
+
+    private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+        Log.i(TAG, msg);
+        if (pw != null) {
+            pw.println(msg);
+            pw.flush();
+        }
+    }
+
+    /**
+     * Writes the trace buffer to disk. This method has no internal synchronization and should be
+     * externally synchronized
+     */
+    private void writeTraceToFileLocked() {
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
+            mBuffer.writeTraceToFile(mTraceFile);
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to write buffer to file", e);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 9946cc3..8ad4d76 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -3,6 +3,7 @@
     srcs: ["java/**/*.java"],
     static_libs: [
         "netd_aidl_interface-java",
+        "networkstack-aidl-interfaces-java",
     ]
 }
 
diff --git a/core/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
similarity index 100%
rename from core/java/android/net/dhcp/DhcpServerCallbacks.java
rename to services/net/java/android/net/dhcp/DhcpServerCallbacks.java
diff --git a/core/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
similarity index 100%
rename from core/java/android/net/ip/IpClientCallbacks.java
rename to services/net/java/android/net/ip/IpClientCallbacks.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 0355e84..5cb6cbb 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -556,16 +556,6 @@
     }
 
     @Override
-    public byte[] getPermissionGrantBackup(int userId) throws RemoteException {
-        return new byte[0];
-    }
-
-    @Override
-    public void restorePermissionGrants(byte[] backup, int userId) throws RemoteException {
-
-    }
-
-    @Override
     public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates)
         throws RemoteException {
         return null;
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index 5900fc5..01759d2 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -98,6 +98,8 @@
 
         mColorDisplayService = new ColorDisplayService(mContext);
         mBinderService = mColorDisplayService.new BinderService();
+        LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
+                        mColorDisplayService.new ColorDisplayServiceInternal());
     }
 
     @After
@@ -110,6 +112,8 @@
 
         mUserId = UserHandle.USER_NULL;
         mContext = null;
+
+        LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
     }
 
     @AfterClass
@@ -979,6 +983,99 @@
         assertActiveColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
     }
 
+    @Test
+    public void displayWhiteBalance_enable() {
+        setWhiteBalance(true /* Enable DWB Setting */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+        mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        assertDwbActive(true);
+    }
+
+    @Test
+    public void displayWhiteBalance_disableAfterNightDisplayEnable() {
+        setWhiteBalance(true /* Enable DWB Setting */);
+
+        startService();
+        /* Enable nightlight */
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        /* Since we are using FakeSettingsProvider which could not trigger observer change,
+         * force an update here.*/
+        mColorDisplayService.updateDisplayWhiteBalanceStatus();
+        assertDwbActive(false);
+    }
+
+    @Test
+    public void displayWhiteBalance_enableAfterNightDisplayDisable() {
+        setWhiteBalance(true /* Enable DWB Setting */);
+        startService();
+        /* Enable nightlight */
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        mColorDisplayService.updateDisplayWhiteBalanceStatus();
+        assertDwbActive(false);
+
+        /* Disable nightlight */
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+        mColorDisplayService.updateDisplayWhiteBalanceStatus();
+        assertDwbActive(true);
+    }
+
+    @Test
+    public void displayWhiteBalance_enableAfterLinearColorMode() {
+        setWhiteBalance(true /* Enable DWB Setting */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+        startService();
+        mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+
+        mColorDisplayService.updateDisplayWhiteBalanceStatus();
+        assertDwbActive(true);
+    }
+
+    @Test
+    public void displayWhiteBalance_setTemperatureOverMax() {
+        int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+
+        ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+                        ColorDisplayService.ColorDisplayServiceInternal.class);
+        cdsInternal.setDisplayWhiteBalanceColorTemperature(max+1);
+
+        assertWithMessage("Unexpected temperature set")
+                .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+                .isEqualTo(max);
+    }
+
+    @Test
+    public void displayWhiteBalance_setTemperatureBelowMin() {
+        int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+
+        ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+                        ColorDisplayService.ColorDisplayServiceInternal.class);
+        cdsInternal.setDisplayWhiteBalanceColorTemperature(min - 1);
+
+        assertWithMessage("Unexpected temperature set")
+                .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+                .isEqualTo(min);
+    }
+
+    @Test
+    public void displayWhiteBalance_setValidTemperature() {
+        int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+        int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+        int valToSet = (min + max) / 2;
+
+        ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+                        ColorDisplayService.ColorDisplayServiceInternal.class);
+        cdsInternal.setDisplayWhiteBalanceColorTemperature(valToSet);
+
+        assertWithMessage("Unexpected temperature set")
+                .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+                .isEqualTo(valToSet);
+    }
+
     /**
      * Configures Night display to use a custom schedule.
      *
@@ -1041,6 +1138,16 @@
     }
 
     /**
+     * Configures the Display White Balance setting state.
+     *
+     * @param state {@code true} if display white balance should be enabled
+     */
+    private void setWhiteBalance(boolean state) {
+        Secure.putIntForUser(mContext.getContentResolver(),
+                Secure.DISPLAY_WHITE_BALANCE_ENABLED, state ? 1 : 0, mUserId);
+    }
+
+    /**
      * Configures color mode.
      */
     private void setColorMode(int colorMode) {
@@ -1111,6 +1218,17 @@
     }
 
     /**
+     * Convenience method for asserting that the DWB active status matches expectation.
+     *
+     * @param enabled the expected active status.
+     */
+    private void assertDwbActive(boolean enabled) {
+        assertWithMessage("Incorrect Display White Balance state")
+                .that(mColorDisplayService.mDisplayWhiteBalanceTintController.isActivated())
+                .isEqualTo(enabled);
+    }
+
+    /**
      * Convenience for making a {@link LocalTime} instance with an offset relative to now.
      *
      * @param offsetMinutes the offset relative to now (in minutes)
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 6d28ed1..50734ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -55,8 +55,8 @@
 
 import com.android.internal.os.AtomicFile;
 import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerInternal;
 import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import org.junit.After;
 import org.junit.Before;
@@ -88,7 +88,8 @@
         writeOldFiles();
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         Settings settings =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -103,7 +104,8 @@
         writeOldFiles();
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         Settings settings =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -120,7 +122,8 @@
         writeOldFiles();
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         Settings settings =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -143,7 +146,8 @@
         writeOldFiles();
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         Settings settings =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -313,7 +317,8 @@
         writeOldFiles();
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         Settings settings =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -507,7 +512,8 @@
     public void testUpdatePackageSetting03() {
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         final Settings testSettings01 =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         final SharedUserSetting testUserSetting01 = createSharedUserSetting(
@@ -625,7 +631,8 @@
     public void testCreateNewSetting03() {
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+        PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+                lock);
         final Settings testSettings01 =
                 new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
         final SharedUserSetting testUserSetting01 = createSharedUserSetting(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
index 2b8e307..b299f0d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -36,11 +36,10 @@
 import org.junit.Test;
 
 import java.io.File;
-import java.io.IOException;
 
 
 /**
- * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ * Test class for {@link WindowTraceBuffer}.
  *
  * Build/Install/Run:
  *  atest WmTests:WindowTraceBufferTest
@@ -49,12 +48,15 @@
 @Presubmit
 public class WindowTraceBufferTest {
     private File mFile;
+    private WindowTraceBuffer mBuffer;
 
     @Before
     public void setUp() throws Exception {
         final Context testContext = getInstrumentation().getContext();
         mFile = testContext.getFileStreamPath("tracing_test.dat");
         mFile.delete();
+
+        mBuffer = new WindowTraceBuffer(10);
     }
 
     @After
@@ -63,145 +65,112 @@
     }
 
     @Test
-    public void testTraceQueueBuffer_addItem() throws Exception {
-        ProtoOutputStream toWrite1 = getDummy(1);
-        ProtoOutputStream toWrite2 = getDummy(2);
-        ProtoOutputStream toWrite3 = getDummy(3);
-        final int objectSize = toWrite1.getRawSize();
-        final int bufferCapacity = objectSize * 2;
-
-        final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
-
-        buffer.add(toWrite1);
-        byte[] toWrite1Bytes = toWrite1.getBytes();
-        assertTrue("First element should be in the list",
-                buffer.contains(toWrite1Bytes));
-
-        buffer.add(toWrite2);
-        byte[] toWrite2Bytes = toWrite2.getBytes();
-        assertTrue("First element should be in the list",
-                buffer.contains(toWrite1Bytes));
-        assertTrue("Second element should be in the list",
-                buffer.contains(toWrite2Bytes));
-
-        buffer.add(toWrite3);
-        byte[] toWrite3Bytes = toWrite3.getBytes();
-        assertTrue("First element should be in the list",
-                buffer.contains(toWrite1Bytes));
-        assertTrue("Second element should be in the list",
-                buffer.contains(toWrite2Bytes));
-        assertTrue("Third element should not be in the list",
-                !buffer.contains(toWrite3Bytes));
-
-        assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
-        assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
-                buffer.mBufferSize, bufferCapacity);
-        assertEquals("Buffer is full, available space should be 0",
-                buffer.getAvailableSpace(), 0);
-    }
-
-    @Test
-    public void testTraceRingBuffer_addItem() throws Exception {
+    public void test_addItem() {
         ProtoOutputStream toWrite = getDummy(1);
         final int objectSize = toWrite.getRawSize();
+        mBuffer.setCapacity(objectSize);
+        mBuffer.resetBuffer();
 
-        final WindowTraceBuffer buffer = buildRingBuffer(objectSize);
+        Preconditions.checkArgument(mBuffer.size() == 0);
 
-        Preconditions.checkArgument(buffer.mBuffer.isEmpty());
+        mBuffer.add(toWrite);
 
-        buffer.add(toWrite);
-
-        assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1);
+        assertEquals("Item was not added to the buffer", 1, mBuffer.size());
         assertEquals("Total buffer getSize differs from inserted object",
-                buffer.mBufferSize, objectSize);
-        assertEquals("Available buffer space does not match used one",
-                buffer.getAvailableSpace(), 0);
+                mBuffer.getBufferSize(), objectSize);
+        assertEquals("Available buffer space does not match used one", 0,
+                mBuffer.getAvailableSpace());
     }
 
     @Test
-    public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception {
+    public void test_addItemMustOverwriteOne() {
         ProtoOutputStream toWrite1 = getDummy(1);
         ProtoOutputStream toWrite2 = getDummy(2);
         ProtoOutputStream toWrite3 = getDummy(3);
         final int objectSize = toWrite1.getRawSize();
-
         final int bufferCapacity = objectSize * 2 + 1;
-        final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+        mBuffer.setCapacity(bufferCapacity);
+        mBuffer.resetBuffer();
 
-        buffer.add(toWrite1);
+        mBuffer.add(toWrite1);
         byte[] toWrite1Bytes = toWrite1.getBytes();
         assertTrue("First element should be in the list",
-                buffer.contains(toWrite1Bytes));
+                mBuffer.contains(toWrite1Bytes));
 
-        buffer.add(toWrite2);
+        mBuffer.add(toWrite2);
         byte[] toWrite2Bytes = toWrite2.getBytes();
         assertTrue("First element should be in the list",
-                buffer.contains(toWrite1Bytes));
+                mBuffer.contains(toWrite1Bytes));
         assertTrue("Second element should be in the list",
-                buffer.contains(toWrite2Bytes));
+                mBuffer.contains(toWrite2Bytes));
 
-        buffer.add(toWrite3);
+        mBuffer.add(toWrite3);
         byte[] toWrite3Bytes = toWrite3.getBytes();
         assertTrue("First element should not be in the list",
-                !buffer.contains(toWrite1Bytes));
+                !mBuffer.contains(toWrite1Bytes));
         assertTrue("Second element should be in the list",
-                buffer.contains(toWrite2Bytes));
+                mBuffer.contains(toWrite2Bytes));
         assertTrue("Third element should be in the list",
-                buffer.contains(toWrite3Bytes));
-        assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+                mBuffer.contains(toWrite3Bytes));
+        assertEquals("Buffer should have 2 elements", 2, mBuffer.size());
         assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
-                buffer.mBufferSize, bufferCapacity - 1);
-        assertEquals(" Buffer is full, available space should be 0",
-                buffer.getAvailableSpace(), 1);
+                mBuffer.getBufferSize(), bufferCapacity - 1);
+        assertEquals(" Buffer is full, available space should be 0", 1,
+                mBuffer.getAvailableSpace());
     }
 
     @Test
-    public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception {
+    public void test_addItemMustOverwriteMultiple() {
         ProtoOutputStream toWriteSmall1 = getDummy(1);
         ProtoOutputStream toWriteSmall2 = getDummy(2);
         final int objectSize = toWriteSmall1.getRawSize();
-
         final int bufferCapacity = objectSize * 2;
-        final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+        mBuffer.setCapacity(bufferCapacity);
+        mBuffer.resetBuffer();
 
         ProtoOutputStream toWriteBig = new ProtoOutputStream();
         toWriteBig.write(MAGIC_NUMBER, 1);
         toWriteBig.write(MAGIC_NUMBER, 2);
 
-        buffer.add(toWriteSmall1);
+        mBuffer.add(toWriteSmall1);
         byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes();
         assertTrue("First element should be in the list",
-                buffer.contains(toWriteSmall1Bytes));
+                mBuffer.contains(toWriteSmall1Bytes));
 
-        buffer.add(toWriteSmall2);
+        mBuffer.add(toWriteSmall2);
         byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes();
         assertTrue("First element should be in the list",
-                buffer.contains(toWriteSmall1Bytes));
+                mBuffer.contains(toWriteSmall1Bytes));
         assertTrue("Second element should be in the list",
-                buffer.contains(toWriteSmall2Bytes));
+                mBuffer.contains(toWriteSmall2Bytes));
 
-        buffer.add(toWriteBig);
+        mBuffer.add(toWriteBig);
         byte[] toWriteBigBytes = toWriteBig.getBytes();
         assertTrue("Third element should overwrite all others",
-                !buffer.contains(toWriteSmall1Bytes));
+                !mBuffer.contains(toWriteSmall1Bytes));
         assertTrue("Third element should overwrite all others",
-                !buffer.contains(toWriteSmall2Bytes));
+                !mBuffer.contains(toWriteSmall2Bytes));
         assertTrue("Third element should overwrite all others",
-                buffer.contains(toWriteBigBytes));
+                mBuffer.contains(toWriteBigBytes));
 
-        assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1);
+        assertEquals(" Buffer should have only 1 big element", 1, mBuffer.size());
         assertEquals(String.format(" Buffer is full, used space should be %d", bufferCapacity),
-                buffer.mBufferSize, bufferCapacity);
-        assertEquals(" Buffer is full, available space should be 0",
-                buffer.getAvailableSpace(), 0);
+                mBuffer.getBufferSize(), bufferCapacity);
+        assertEquals(" Buffer is full, available space should be 0", 0,
+                mBuffer.getAvailableSpace());
     }
 
-    private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException {
-        return new WindowTraceBuffer.Builder()
-                .setContinuousMode(true)
-                .setBufferCapacity(capacity)
-                .setTraceFile(mFile)
-                .build();
+    @Test
+    public void test_startResetsBuffer() {
+        ProtoOutputStream toWrite = getDummy(1);
+        mBuffer.resetBuffer();
+        Preconditions.checkArgument(mBuffer.size() == 0);
+
+        mBuffer.add(toWrite);
+        assertEquals("Item was not added to the buffer", 1, mBuffer.size());
+        mBuffer.resetBuffer();
+        assertEquals("Buffer should be empty after reset", 0, mBuffer.size());
+        assertEquals("Buffer size should be 0 after reset", 0, mBuffer.getBufferSize());
     }
 
     private ProtoOutputStream getDummy(int value) {
@@ -212,7 +181,4 @@
         return toWrite;
     }
 
-    private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
-        return new WindowTraceQueueBuffer(size, mFile, false);
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 3c6e240..8358fdd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -88,8 +88,7 @@
         mFile.delete();
 
         mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
-                new WindowManagerGlobalLock());
-        mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
+                new WindowManagerGlobalLock(), 1024);
     }
 
     @After
@@ -103,13 +102,13 @@
     }
 
     @Test
-    public void isEnabled_returnsTrueAfterStart() throws Exception {
+    public void isEnabled_returnsTrueAfterStart() {
         mWindowTracing.startTrace(mock(PrintWriter.class));
         assertTrue(mWindowTracing.isEnabled());
     }
 
     @Test
-    public void isEnabled_returnsFalseAfterStop() throws Exception {
+    public void isEnabled_returnsFalseAfterStop() {
         mWindowTracing.startTrace(mock(PrintWriter.class));
         mWindowTracing.stopTrace(mock(PrintWriter.class));
         assertFalse(mWindowTracing.isEnabled());
@@ -133,6 +132,8 @@
         mWindowTracing.startTrace(mock(PrintWriter.class));
         mWindowTracing.stopTrace(mock(PrintWriter.class));
 
+        assertTrue("Trace file should exist", mFile.exists());
+
         byte[] header = new byte[MAGIC_HEADER.length];
         try (InputStream is = new FileInputStream(mFile)) {
             assertEquals(MAGIC_HEADER.length, is.read(header));
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index f1ddfe4..8feed7f 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -15,7 +15,6 @@
  */
 package com.android.server.usage;
 
-import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
@@ -302,27 +301,6 @@
                 UsageStats usageStats = packageStats.valueAt(i);
                 usageStats.update(null, timeStamp, eventType, instanceId);
             }
-        } else if (eventType == ACTIVITY_DESTROYED) {
-            UsageStats usageStats = packageStats.get(packageName);
-            if (usageStats != null) {
-                // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED
-                // to ACTIVITY_STOPPED and add to event list.
-                // Otherwise do not add anything to event list. (Because we want to save space
-                // and we do not want a ACTIVITY_STOPPED followed by
-                // ACTIVITY_DESTROYED in event list).
-                final int index = usageStats.mActivities.indexOfKey(instanceId);
-                if (index >= 0) {
-                    final int type = usageStats.mActivities.valueAt(index);
-                    if (type != ACTIVITY_STOPPED) {
-                        Event event = new Event(ACTIVITY_STOPPED, timeStamp);
-                        event.mPackage = packageName;
-                        event.mClass = className;
-                        event.mInstanceId = instanceId;
-                        addEvent(event);
-                    }
-                }
-                usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId);
-            }
         } else {
             UsageStats usageStats = getOrCreateUsageStats(packageName);
             usageStats.update(className, timeStamp, eventType, instanceId);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index af5278f..ebb0210 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -145,8 +145,16 @@
     AppTimeLimitController mAppTimeLimit;
 
     final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
-    final SparseArray<String> mVisibleActivities = new SparseArray();
+    final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
 
+    private static class ActivityData {
+        private final String mTaskRootPackage;
+        private final String mTaskRootClass;
+        private ActivityData(String taskRootPackage, String taskRootClass) {
+            mTaskRootPackage = taskRootPackage;
+            mTaskRootClass = taskRootClass;
+        }
+    }
 
     private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
             new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@@ -464,47 +472,57 @@
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             convertToSystemTimeLocked(event);
 
-            if (event.getPackageName() != null
-                    && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) {
+            if (event.mPackage != null
+                    && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) {
                 event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            service.reportEvent(event);
-
-            mAppStandby.reportEvent(event, elapsedRealtime, userId);
-
-            String packageName;
-
-            switch(mUsageSource) {
-                case USAGE_SOURCE_CURRENT_ACTIVITY:
-                    packageName = event.getPackageName();
-                    break;
-                case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
-                default:
-                    packageName = event.getTaskRootPackageName();
-                    if (packageName == null) {
-                        packageName = event.getPackageName();
-                    }
-                    break;
-            }
-
             switch (event.mEventType) {
                 case Event.ACTIVITY_RESUMED:
-                    synchronized (mVisibleActivities) {
-                        // check if this activity has already been resumed
-                        if (mVisibleActivities.get(event.mInstanceId) != null) break;
-                        mVisibleActivities.put(event.mInstanceId, event.getClassName());
-                        try {
-                            mAppTimeLimit.noteUsageStart(packageName, userId);
-                        } catch (IllegalArgumentException iae) {
-                            Slog.e(TAG, "Failed to note usage start", iae);
+                    // check if this activity has already been resumed
+                    if (mVisibleActivities.get(event.mInstanceId) != null) break;
+                    mVisibleActivities.put(event.mInstanceId,
+                            new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+                    try {
+                        switch(mUsageSource) {
+                            case USAGE_SOURCE_CURRENT_ACTIVITY:
+                                mAppTimeLimit.noteUsageStart(event.mPackage, userId);
+                                break;
+                            case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+                            default:
+                                mAppTimeLimit.noteUsageStart(event.mTaskRootPackage, userId);
+                                break;
+                        }
+                    } catch (IllegalArgumentException iae) {
+                        Slog.e(TAG, "Failed to note usage start", iae);
+                    }
+                    break;
+                case Event.ACTIVITY_PAUSED:
+                    if (event.mTaskRootPackage == null) {
+                        // Task Root info is missing. Repair the event based on previous data
+                        final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
+                        if (prevData == null) {
+                            Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+                                    + "/" + event.mClass + " event : " + event.mEventType
+                                    + " instanceId : " + event.mInstanceId + ")");
+                        } else {
+                            event.mTaskRootPackage = prevData.mTaskRootPackage;
+                            event.mTaskRootClass = prevData.mTaskRootClass;
                         }
                     }
                     break;
-                case Event.ACTIVITY_STOPPED:
                 case Event.ACTIVITY_DESTROYED:
+                    // Treat activity destroys like activity stops.
+                    event.mEventType = Event.ACTIVITY_STOPPED;
+                    // Fallthrough
+                case Event.ACTIVITY_STOPPED:
+                    final ActivityData prevData =
+                            mVisibleActivities.removeReturnOld(event.mInstanceId);
+                    if (prevData == null) {
+                        // The activity stop was already handled.
+                        return;
+                    }
+
                     ArraySet<String> tokens;
                     synchronized (mUsageReporters) {
                         tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
@@ -517,7 +535,7 @@
                                 final String token = tokens.valueAt(i);
                                 try {
                                     mAppTimeLimit.noteUsageStop(
-                                            buildFullToken(event.getPackageName(), token), userId);
+                                            buildFullToken(event.mPackage, token), userId);
                                 } catch (IllegalArgumentException iae) {
                                     Slog.w(TAG, "Failed to stop usage for during reporter death: "
                                             + iae);
@@ -525,18 +543,32 @@
                             }
                         }
                     }
-
-                    synchronized (mVisibleActivities) {
-                        if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
-                            try {
-                                mAppTimeLimit.noteUsageStop(packageName, userId);
-                            } catch (IllegalArgumentException iae) {
-                                Slog.w(TAG, "Failed to note usage stop", iae);
-                            }
+                    if (event.mTaskRootPackage == null) {
+                        // Task Root info is missing. Repair the event based on previous data
+                        event.mTaskRootPackage = prevData.mTaskRootPackage;
+                        event.mTaskRootClass = prevData.mTaskRootClass;
+                    }
+                    try {
+                        switch(mUsageSource) {
+                            case USAGE_SOURCE_CURRENT_ACTIVITY:
+                                mAppTimeLimit.noteUsageStop(event.mPackage, userId);
+                                break;
+                            case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+                            default:
+                                mAppTimeLimit.noteUsageStop(event.mTaskRootPackage, userId);
+                                break;
                         }
+                    } catch (IllegalArgumentException iae) {
+                        Slog.w(TAG, "Failed to note usage stop", iae);
                     }
                     break;
             }
+
+            final UserUsageStatsService service =
+                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+            service.reportEvent(event);
+
+            mAppStandby.reportEvent(event, elapsedRealtime, userId);
         }
     }
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index bd0d4ae..ae12a17 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -623,7 +623,7 @@
             "android.telecom.event.HANDOVER_FAILED";
 
     /**
-     * Connection extra key used to store SIP invite fields for an incoming call for IMS calls
+     * String Connection extra key used to store SIP invite fields for an incoming call for IMS call
      */
     public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
 
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 73f0556..d5c7079 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -266,6 +266,11 @@
     public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
     public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
     public static final String EXTRA_IS_CALL_PULL = "CallPull";
+
+    /**
+     * String extra property
+     *  Containing fields from the SIP INVITE message for an IMS call
+     */
     public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS =
                                   "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
 
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index ab10800..0cb8f22 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -9,10 +9,12 @@
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public String[] getNamesForUids(int[]);
     method public String getPermissionControllerPackageName();
+    method public int getPermissionFlags(String, String, android.os.UserHandle);
     method @NonNull public String getServicesSystemSharedLibraryPackageName();
     method @NonNull public String getSharedSystemSharedLibraryPackageName();
     method public void grantRuntimePermission(String, String, android.os.UserHandle);
     method public void revokeRuntimePermission(String, String, android.os.UserHandle);
+    method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
   }
 
 }
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5f664f5..9832485 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -435,7 +435,7 @@
   const size_t NS = pool->size();
   for (size_t s=0; s<NS; s++) {
     String8 str = pool->string8ObjectAt(s);
-    printer->Print(StringPrintf("String #%zd: %s\n", s, str.string()));
+    printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
   }
 }
 
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 2f8ca2d..c188782 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1084,7 +1084,7 @@
   // Create a overlayable entry grouping that represents this <overlayable>
   auto overlayable = std::make_shared<Overlayable>(
       overlayable_name.value(), (overlayable_actor) ? overlayable_actor.value() : "",
-      out_resource->source);
+      source_);
 
   bool error = false;
   std::string comment;
@@ -1113,6 +1113,13 @@
     const std::string& element_name = parser->element_name();
     const std::string& element_namespace = parser->element_namespace();
     if (element_namespace.empty() && element_name == "item") {
+      if (current_policies == OverlayableItem::Policy::kNone) {
+        diag_->Error(DiagMessage(element_source)
+                         << "<item> within an <overlayable> must be inside a <policy> block");
+        error = true;
+        continue;
+      }
+
       // Items specify the name and type of resource that should be overlayable
       Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
       if (!item_name) {
@@ -1169,6 +1176,8 @@
             current_policies |= OverlayableItem::Policy::kSystem;
           } else if (trimmed_part == "vendor") {
             current_policies |= OverlayableItem::Policy::kVendor;
+          } else if (trimmed_part == "signature") {
+            current_policies |= OverlayableItem::Policy::kSignature;
           } else {
             diag_->Error(DiagMessage(element_source)
                          << "<policy> has unsupported type '" << trimmed_part << "'");
@@ -1176,6 +1185,11 @@
             continue;
           }
         }
+      } else {
+        diag_->Error(DiagMessage(element_source)
+                         << "<policy> must have a 'type' attribute");
+        error = true;
+        continue;
       }
     } else if (!ShouldIgnoreElement(element_namespace, element_name)) {
       diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 827c7de..25b76b0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -894,8 +894,10 @@
 TEST_F(ResourceParserTest, ParseOverlayable) {
   std::string input = R"(
       <overlayable name="Name" actor="overlay://theme">
-        <item type="string" name="foo" />
-        <item type="drawable" name="bar" />
+          <policy type="signature">
+            <item type="string" name="foo" />
+            <item type="drawable" name="bar" />
+          </policy>
       </overlayable>)";
   ASSERT_TRUE(TestParse(input));
 
@@ -906,7 +908,7 @@
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
 
   search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
   ASSERT_TRUE(search_result);
@@ -915,7 +917,7 @@
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
 }
 
 TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
@@ -931,7 +933,6 @@
 TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
   std::string input = R"(
       <overlayable name="Name">
-        <item type="string" name="foo" />
         <policy type="product">
           <item type="string" name="bar" />
         </policy>
@@ -944,23 +945,18 @@
         <policy type="public">
           <item type="string" name="faz" />
         </policy>
+        <policy type="signature">
+          <item type="string" name="foz" />
+        </policy>
       </overlayable>)";
   ASSERT_TRUE(TestParse(input));
 
-  auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+  auto search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
-
-  search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
-  ASSERT_TRUE(search_result);
-  ASSERT_THAT(search_result.value().entry, NotNull());
-  ASSERT_TRUE(search_result.value().entry->overlayable_item);
-  result_overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
@@ -986,6 +982,30 @@
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/foz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) {
+  std::string input = R"(
+      <overlayable name="Name">
+        <item type="string" name="foo" />
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable name="Name">
+        <policy>
+          <item name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
 }
 
 TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 7ca99ea..32dfd26 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -92,6 +92,9 @@
 
     // The resource can be overlaid by any overlay on the product partition.
     kProduct = 0x08,
+
+    // The resource can be overlaid by any overlay signed with the same signature as its actor.
+    kSignature = 0x010,
   };
 
   std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index ab4805f..0032960 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -727,7 +727,7 @@
           // This must be a FileReference.
           std::unique_ptr<FileReference> file_ref =
               util::make_unique<FileReference>(dst_pool->MakeRef(
-                  str, StringPool::Context(StringPool::Context::kHighPriority, config), data));
+                  str, StringPool::Context(StringPool::Context::kHighPriority, config)));
           if (type == ResourceType::kRaw) {
             file_ref->type = ResourceFile::Type::kUnknown;
           } else if (util::EndsWith(*file_ref->path, ".xml")) {
@@ -739,7 +739,7 @@
         }
 
         // There are no styles associated with this string, so treat it as a simple string.
-        return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config), data));
+        return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config)));
       }
     } break;
 
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 9a1d942..a2fd7c6 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -138,10 +138,10 @@
 
 // Represents a set of overlayable resources.
 message Overlayable {
-  // The name of the <overlyabale>.
+  // The name of the <overlayable>.
   string name = 1;
 
-  // The location of the <overlyabale> declaration in the source.
+  // The location of the <overlayable> declaration in the source.
   Source source = 2;
 
   // The component responsible for enabling and disabling overlays targeting this <overlayable>.
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index a8c2666..8eabd32 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -165,13 +165,12 @@
   return MakeRefImpl(str, Context{}, true);
 }
 
-StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context,
-                                    Maybe<size_t> index) {
-  return MakeRefImpl(str, context, true, index);
+StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context) {
+  return MakeRefImpl(str, context, true);
 }
 
 StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& context,
-                                        bool unique, Maybe<size_t> index) {
+                                        bool unique) {
   if (unique) {
     auto range = indexed_strings_.equal_range(str);
     for (auto iter = range.first; iter != range.second; ++iter) {
@@ -181,26 +180,15 @@
     }
   }
 
-  const size_t size = strings_.size();
-  // Insert the string at the end of the string vector if no index is specified
-  const size_t insertion_index = index ? index.value() : size;
-
   std::unique_ptr<Entry> entry(new Entry());
   entry->value = str.to_string();
   entry->context = context;
-  entry->index_ = insertion_index;
+  entry->index_ = strings_.size();
   entry->ref_ = 0;
   entry->pool_ = this;
 
   Entry* borrow = entry.get();
-  if (insertion_index == size) {
-    strings_.emplace_back(std::move(entry));
-  } else {
-    // Allocate enough space for the string at the index
-    strings_.resize(std::max(insertion_index + 1, size));
-    strings_[insertion_index] = std::move(entry);
-  }
-
+  strings_.emplace_back(std::move(entry));
   indexed_strings_.insert(std::make_pair(StringPiece(borrow->value), borrow));
   return Ref(borrow);
 }
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index 115d5d3..1006ca9 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -166,8 +166,7 @@
 
   // Adds a string to the pool, unless it already exists, with a context object that can be used
   // when sorting the string pool. Returns a reference to the string in the pool.
-  Ref MakeRef(const android::StringPiece& str, const Context& context,
-              Maybe<size_t> index = {});
+  Ref MakeRef(const android::StringPiece& str, const Context& context);
 
   // Adds a string from another string pool. Returns a reference to the string in the string pool.
   Ref MakeRef(const Ref& ref);
@@ -211,8 +210,7 @@
 
   static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag);
 
-  Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique,
-                  Maybe<size_t> index = {});
+  Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
   void ReAssignIndices();
 
   std::vector<std::unique_ptr<Entry>> strings_;
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 648be7d..9a7238b 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -84,24 +84,6 @@
   EXPECT_THAT(ref_c.index(), Eq(2u));
 }
 
-TEST(StringPoolTest, AssignStringIndex) {
-  StringPool pool;
-
-  StringPool::Ref ref_a = pool.MakeRef("0", StringPool::Context{}, 0u);
-  StringPool::Ref ref_b = pool.MakeRef("1", StringPool::Context{}, 1u);
-  StringPool::Ref ref_c = pool.MakeRef("5", StringPool::Context{}, 5u);
-  StringPool::Ref ref_d = pool.MakeRef("2", StringPool::Context{}, 2u);
-  StringPool::Ref ref_e = pool.MakeRef("4", StringPool::Context{}, 4u);
-  StringPool::Ref ref_f = pool.MakeRef("3", StringPool::Context{}, 3u);
-
-  EXPECT_THAT(ref_a.index(), Eq(0u));
-  EXPECT_THAT(ref_b.index(), Eq(1u));
-  EXPECT_THAT(ref_d.index(), Eq(2u));
-  EXPECT_THAT(ref_f.index(), Eq(3u));
-  EXPECT_THAT(ref_e.index(), Eq(4u));
-  EXPECT_THAT(ref_c.index(), Eq(5u));
-}
-
 TEST(StringPoolTest, PruneStringsWithNoReferences) {
   StringPool pool;
 
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 7a74ba9..0cf86cc 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -43,7 +43,8 @@
 
 class IApkSerializer {
  public:
-  IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
+  IApkSerializer(IAaptContext* context, const Source& source) : context_(context),
+                                                                source_(source) {}
 
   virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
                             IArchiveWriter* writer, uint32_t compression_flags) = 0;
@@ -167,7 +168,7 @@
       std::unique_ptr<io::IData> data = file->file->OpenAsData();
       if (!data) {
         context_->GetDiagnostics()->Error(DiagMessage(source_)
-                                         << "failed to open file " << *file->path);
+                                          << "failed to open file " << *file->path);
         return false;
       }
 
@@ -175,7 +176,7 @@
       std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
       if (xml == nullptr) {
         context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: "
-                                          << error);
+                                                               << error);
         return false;
       }
 
@@ -256,9 +257,6 @@
 int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer,
             ApkFormat output_format, TableFlattenerOptions table_flattener_options,
             XmlFlattenerOptions xml_flattener_options) {
-  // Do not change the ordering of strings in the values string pool
-  table_flattener_options.sort_stringpool_entries = false;
-
   unique_ptr<IApkSerializer> serializer;
   if (output_format == ApkFormat::kBinary) {
     serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options,
@@ -274,7 +272,7 @@
   io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
   if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/,
                                 output_writer, (manifest != nullptr && manifest->WasCompressed())
-                                ? ArchiveEntry::kCompress : 0u)) {
+                                               ? ArchiveEntry::kCompress : 0u)) {
     context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
                                      << "failed to serialize AndroidManifest.xml");
     return 1;
@@ -303,8 +301,7 @@
               if (files_written.insert(*file->path).second) {
                 if (!serializer->SerializeFile(file, output_writer)) {
                   context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
-                                                       << "failed to serialize file "
-                                                       << *file->path);
+                                                   << "failed to serialize file " << *file->path);
                   return 1;
                 }
               }
@@ -338,7 +335,7 @@
 
     if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) {
       context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
-                                       << "failed to copy file " << path);
+                                           << "failed to copy file " << path);
       return 1;
     }
   }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 8463046..4961aa5 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -400,7 +400,8 @@
 
 static bool IsVectorElement(const std::string& name) {
   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
-         name == "objectAnimator" || name == "gradient" || name == "animated-selector";
+         name == "objectAnimator" || name == "gradient" || name == "animated-selector" ||
+         name == "set";
 }
 
 template <typename T>
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 40aaa05..59eb9ec2 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -401,7 +401,6 @@
     if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
       Visibility visibility;
       visibility.level = Visibility::Level::kPublic;
-      visibility.source = source_.WithLine(0);
       if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) {
         return false;
       }
@@ -448,7 +447,6 @@
                                                       arraysize(header->name)));
   overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
                                                        arraysize(header->name)));
-  overlayable->source = source_.WithLine(0);
 
   ResChunkPullParser parser(GetChunkData(chunk),
                             GetChunkDataLen(chunk));
@@ -473,6 +471,10 @@
           & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
         policies |= OverlayableItem::Policy::kProduct;
       }
+      if (policy_header->policy_flags
+          & ResTable_overlayable_policy_header::POLICY_SIGNATURE) {
+        policies |= OverlayableItem::Policy::kSignature;
+      }
 
       const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
           ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
@@ -491,7 +493,6 @@
         }
 
         OverlayableItem overlayable_item(overlayable);
-        overlayable_item.source = source_.WithLine(0);
         overlayable_item.policies = policies;
         if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
           return false;
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 9d341cc..d677317 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -274,7 +274,9 @@
       FlattenLibrarySpec(buffer);
     }
 
-    FlattenOverlayable(buffer);
+    if (!FlattenOverlayable(buffer)) {
+      return false;
+    }
 
     pkg_writer.Finish();
     return true;
@@ -468,23 +470,29 @@
           overlayable_chunk = &chunk;
         }
 
+        if (item.policies == 0) {
+          context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+                                                << "overlayable "
+                                                << entry->name
+                                                << " does not specify policy");
+          return false;
+        }
+
         uint32_t policy_flags = 0;
-        if (item.policies == OverlayableItem::Policy::kNone) {
-          // Encode overlayable entries defined without a policy as publicly overlayable
+        if (item.policies & OverlayableItem::Policy::kPublic) {
           policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        } else {
-          if (item.policies & OverlayableItem::Policy::kPublic) {
-            policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-          }
-          if (item.policies & OverlayableItem::Policy::kSystem) {
-            policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
-          }
-          if (item.policies & OverlayableItem::Policy::kVendor) {
-            policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
-          }
-          if (item.policies & OverlayableItem::Policy::kProduct) {
-            policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
-          }
+        }
+        if (item.policies & OverlayableItem::Policy::kSystem) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+        }
+        if (item.policies & OverlayableItem::Policy::kVendor) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+        }
+        if (item.policies & OverlayableItem::Policy::kProduct) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+        }
+        if (item.policies & OverlayableItem::Policy::kSignature) {
+          policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE;
         }
 
         auto policy = overlayable_chunk->policy_ids.find(policy_flags);
@@ -702,17 +710,15 @@
 }  // namespace
 
 bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
-  if (options_.sort_stringpool_entries) {
-    // We must do this before writing the resources, since the string pool IDs may change.
-    table->string_pool.Prune();
-    table->string_pool.Sort([](const StringPool::Context &a, const StringPool::Context &b) -> int {
-      int diff = util::compare(a.priority, b.priority);
-      if (diff == 0) {
-        diff = a.config.compare(b.config);
-      }
-      return diff;
-    });
-  }
+  // We must do this before writing the resources, since the string pool IDs may change.
+  table->string_pool.Prune();
+  table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
+    int diff = util::compare(a.priority, b.priority);
+    if (diff == 0) {
+      diff = a.config.compare(b.config);
+    }
+    return diff;
+  });
 
   // Write the ResTable header.
   ChunkWriter table_writer(buffer_);
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 71330e3..73c1729 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -44,9 +44,6 @@
   // Set of whitelisted resource names to avoid altering in key stringpool
   std::set<std::string> whitelisted_resources;
 
-  // When true, sort the entries in the values string pool by priority and configuration.
-  bool sort_stringpool_entries = true;
-
   // Map from original resource paths to shortened resource paths.
   std::map<std::string, std::string> shortened_path_map;
 };
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index ddc1173..4c5dbec 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -671,9 +671,6 @@
   overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
   overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
 
-  std::string name_three = "com.app.test:integer/overlayable_three_item";
-  OverlayableItem overlayable_item_three(overlayable);
-
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
@@ -683,8 +680,6 @@
           .SetOverlayable(name_one, overlayable_item_one)
           .AddSimple(name_two, ResourceId(0x7f020002))
           .SetOverlayable(name_two, overlayable_item_two)
-          .AddSimple(name_three, ResourceId(0x7f020003))
-          .SetOverlayable(name_three, overlayable_item_three)
           .Build();
 
   ResourceTable output_table;
@@ -713,16 +708,6 @@
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
                                        | OverlayableItem::Policy::kProduct
                                        | OverlayableItem::Policy::kVendor);
-
-  search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
-  ASSERT_TRUE(search_result);
-  ASSERT_THAT(search_result.value().entry, NotNull());
-  ASSERT_TRUE(search_result.value().entry->overlayable_item);
-  overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
-  EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
-  EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
 }
 
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
@@ -745,6 +730,8 @@
 
   std::string name_three = "com.app.test:integer/overlayable_three";
   OverlayableItem overlayable_item_three(group_one);
+  overlayable_item_three.policies |= OverlayableItem::Policy::kSignature;
+
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
@@ -793,7 +780,22 @@
   result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature);
+}
+
+TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
+  auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+  std::string name_zero = "com.app.test:integer/overlayable_zero";
+  OverlayableItem overlayable_item_zero(group);
+
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.test", 0x7f)
+          .AddSimple(name_zero, ResourceId(0x7f020000))
+          .SetOverlayable(name_zero, overlayable_item_zero)
+          .Build();
+  ResourceTable output_table;
+  ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table));
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index aff1b39..06f1bf7 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,6 +390,9 @@
       case pb::OverlayableItem::PRODUCT:
         out_overlayable->policies |= OverlayableItem::Policy::kProduct;
         break;
+      case pb::OverlayableItem::SIGNATURE:
+        out_overlayable->policies |= OverlayableItem::Policy::kSignature;
+        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index b549e23..eb2b1a2 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -309,6 +309,9 @@
   if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
   }
+  if (overlayable_item.policies & OverlayableItem::Policy::kSignature) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
+  }
 
   SerializeSourceToPb(overlayable_item.source, source_pool,
                       pb_overlayable_item->mutable_source());
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index cce3939..d369ac4 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -526,6 +526,10 @@
       "FontPack", "overlay://theme"));
   overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic;
 
+  OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
+      "IconPack", "overlay://theme"));
+  overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature;
+
   OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
       "Other", "overlay://customization"));
   overlayable_item_biz.comment ="comment";
@@ -536,6 +540,7 @@
           .SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
           .SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
           .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
+          .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz)
           .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
           .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
           .Build();
@@ -576,6 +581,14 @@
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
   EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
 
+  search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
+  EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
+  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);