Merge "Add metrics to CrossProfileApps methods." into qt-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index e479c48..36680a1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1635,7 +1635,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
     method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
     method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
-    method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
+    method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method public void sendDeviceCustomizationReadyBroadcast();
     method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 77c3a94..aacf2c1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3205,6 +3205,7 @@
     method public default void setShouldShowIme(int, boolean);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
+    method public default boolean shouldShowIme(int);
     method public default boolean shouldShowSystemDecors(int);
   }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2bd4299..318d90c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3296,7 +3296,10 @@
         INSTALL_STAGED_NOT_READY = 3;
         INSTALL_STAGED_READY = 4;
         INSTALL_SUCCESS = 5;
-        INSTALL_FAILURE = 6;
+        // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
+        // and INSTALL_FAILURE_COMMIT.
+        INSTALL_FAILURE = 6  [deprecated = true];
+        // This enum is for installs that are manually cancelled via the Manual Update UI.
         INSTALL_CANCELLED = 7;
         INSTALLER_ROLLBACK_REQUESTED = 8;
         INSTALLER_ROLLBACK_INITIATED = 9;
@@ -3313,6 +3316,9 @@
         INSTALL_STAGED_CANCEL_REQUESTED = 20;
         INSTALL_STAGED_CANCEL_SUCCESS = 21;
         INSTALL_STAGED_CANCEL_FAILURE = 22;
+        INSTALL_FAILURE_DOWNLOAD = 23;
+        INSTALL_FAILURE_STATE_MISMATCH = 24;
+        INSTALL_FAILURE_COMMIT = 25;
     }
     optional State state = 6;
     // Possible experiment ids for monitoring this push.
@@ -5863,7 +5869,10 @@
         INSTALL_STAGED_NOT_READY = 3;
         INSTALL_STAGED_READY = 4;
         INSTALL_SUCCESS = 5;
-        INSTALL_FAILURE = 6;
+        // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
+        // and INSTALL_FAILURE_COMMIT.
+        INSTALL_FAILURE = 6  [deprecated = true];
+        // This enum is for installs that are manually cancelled via the Manual Update UI.
         INSTALL_CANCELLED = 7;
         INSTALLER_ROLLBACK_REQUESTED = 8;
         INSTALLER_ROLLBACK_INITIATED = 9;
@@ -5880,6 +5889,9 @@
         INSTALL_STAGED_CANCEL_REQUESTED = 20;
         INSTALL_STAGED_CANCEL_SUCCESS = 21;
         INSTALL_STAGED_CANCEL_FAILURE = 22;
+        INSTALL_FAILURE_DOWNLOAD = 23;
+        INSTALL_FAILURE_STATE_MISMATCH = 24;
+        INSTALL_FAILURE_COMMIT = 25;
     }
     optional Status status = 4;
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a95e094..33c0bb9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -6178,15 +6178,7 @@
      * @param activity The component name of the activity that is to be preferred.
      *
      * @hide
-     *
-     * @deprecated This function no longer does anything. It is the platform's
-     * responsibility to assign preferred activities and this cannot be modified
-     * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
-     * an app to be responsible for a particular role and to check current role
-     * holders, see {@link android.app.role.RoleManager}.
      */
-    @Deprecated
     @SystemApi
     public void replacePreferredActivity(@NonNull IntentFilter filter, int match,
             @NonNull List<ComponentName> set, @NonNull ComponentName activity) {
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index a52e96e..b0d399c 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
+
 import java.util.ArrayList;
 
 /**
@@ -240,6 +241,12 @@
             }
             return this;
         }
+
+        /** @hide */
+        public final RowBuilder add(int columnIndex, Object value) {
+            data[(row * columnCount) + columnIndex] = value;
+            return this;
+        }
     }
 
     // AbstractCursor implementation.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 94c8b91..3a4741a 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -978,11 +978,6 @@
          */
         public static final int Q = CUR_DEVELOPMENT;
 
-        /**
-         * Stub for a potential new API level after P.
-         * @hide
-         */
-        public static final int P0 = Q;
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 1aa5b06..2a41c20 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -23,11 +23,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
 import android.os.RemoteException;
 
 import com.android.internal.annotations.Immutable;
@@ -107,11 +104,11 @@
     /**
      * Get set of permissions that have been split into more granular or dependent permissions.
      *
-     * <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
+     * <p>E.g. before {@link android.os.Build.VERSION_CODES#Q} an app that was granted
      * {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
-     * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#P0}
+     * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#Q}
      * the location permission only grants location access while the app is in foreground. This
-     * would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
+     * would break apps that target before {@link android.os.Build.VERSION_CODES#Q}. Hence whenever
      * such an old app asks for a location permission (i.e. the
      * {@link SplitPermissionInfo#getSplitPermission()}), then the
      * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8a21806..b0e980e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11961,6 +11961,36 @@
         public static final String JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants";
 
         /**
+         * Job scheduler QuotaController specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "max_job_count_working=5,max_job_count_rare=2"
+         *
+         * <p>
+         * Type: string
+         *
+         * @hide
+         * @see com.android.server.job.JobSchedulerService.Constants
+         */
+        public static final String JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS =
+                "job_scheduler_quota_controller_constants";
+
+        /**
+         * Job scheduler TimeController specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "skip_not_ready_jobs=true5,other_key=2"
+         *
+         * <p>
+         * Type: string
+         *
+         * @hide
+         * @see com.android.server.job.JobSchedulerService.Constants
+         */
+        public static final String JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS =
+                "job_scheduler_time_controller_constants";
+
+        /**
          * ShortcutManager specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index eeefb4a..dc9c858 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -183,7 +183,6 @@
      */
     @SystemApi
     public static final class PackageConfig implements Parcelable {
-        // TODO: Receive from DeviceConfig flag
         private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
 
         private final String mPackageName;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c2aec6a..a25f2ee 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -508,14 +508,25 @@
      *
      * @param displayId Display ID.
      * @param shouldShow Indicates that the display should show IME.
-     * @see KeyguardManager#isDeviceSecure()
-     * @see KeyguardManager#isDeviceLocked()
      * @hide
      */
     @TestApi
     default void setShouldShowIme(int displayId, boolean shouldShow) {
     }
 
+    /**
+     * Indicates that the display should show IME.
+     *
+     * @param displayId The id of the display.
+     * @return {@code true} if the display should show IME when an input field becomes
+     * focused on it.
+     * @hide
+     */
+    @TestApi
+    default boolean shouldShowIme(int displayId) {
+        return false;
+    }
+
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
          * X position for this window.  With the default gravity it is ignored.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2e4db5c..c349443 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -192,4 +192,13 @@
         } catch (RemoteException e) {
         }
     }
+
+    @Override
+    public boolean shouldShowIme(int displayId) {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().shouldShowIme(displayId);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 417c6e7..042b943 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -25,6 +25,7 @@
 import android.database.ContentObserver;
 import android.os.ServiceManager;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
 import android.provider.Settings;
 import android.service.textclassifier.TextClassifierService;
 import android.view.textclassifier.TextClassifier.TextClassifierType;
@@ -199,7 +200,7 @@
                 getApplicationContext().getContentResolver()
                         .unregisterContentObserver(mSettingsObserver);
                 if (ConfigParser.ENABLE_DEVICE_CONFIG) {
-                    DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+                    DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver);
                 }
             }
         } finally {
@@ -286,7 +287,7 @@
     }
 
     private static final class SettingsObserver extends ContentObserver
-            implements DeviceConfig.OnPropertyChangedListener {
+            implements DeviceConfig.OnPropertiesChangedListener {
 
         private final WeakReference<TextClassificationManager> mTcm;
 
@@ -298,7 +299,7 @@
                     false /* notifyForDescendants */,
                     this);
             if (ConfigParser.ENABLE_DEVICE_CONFIG) {
-                DeviceConfig.addOnPropertyChangedListener(
+                DeviceConfig.addOnPropertiesChangedListener(
                         DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
                         ActivityThread.currentApplication().getMainExecutor(),
                         this);
@@ -311,7 +312,7 @@
         }
 
         @Override
-        public void onPropertyChanged(String namespace, String name, String value) {
+        public void onPropertiesChanged(Properties properties) {
             invalidateSettings();
         }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 8b510a4..1eabbd8 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2586,6 +2586,20 @@
         }
 
         @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            int viewType = getItemViewType(position);
+            if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
         public int getCount() {
             return (int) (
                     getContentPreviewRowCount()
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 76826d3..9e8bd64 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -45,6 +45,7 @@
 import android.webkit.MimeTypeMap;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
 
@@ -450,7 +451,11 @@
 
     @Override
     public String getDocumentType(String documentId) throws FileNotFoundException {
-        final File file = getFileForDocId(documentId);
+        return getDocumentType(documentId, getFileForDocId(documentId));
+    }
+
+    private String getDocumentType(final String documentId, final File file)
+            throws FileNotFoundException {
         if (file.isDirectory()) {
             return Document.MIME_TYPE_DIR;
         } else {
@@ -532,51 +537,63 @@
         return DocumentsContract.openImageThumbnail(file);
     }
 
-    protected RowBuilder includeFile(MatrixCursor result, String docId, File file)
+    protected RowBuilder includeFile(final MatrixCursor result, String docId, File file)
             throws FileNotFoundException {
+        final String[] columns = result.getColumnNames();
+        final RowBuilder row = result.newRow();
+
         if (docId == null) {
             docId = getDocIdForFile(file);
         } else {
             file = getFileForDocId(docId);
         }
+        final String mimeType = getDocumentType(docId, file);
+        row.add(Document.COLUMN_DOCUMENT_ID, docId);
+        row.add(Document.COLUMN_MIME_TYPE, mimeType);
 
-        int flags = 0;
+        final int flagIndex = ArrayUtils.indexOf(columns, Document.COLUMN_FLAGS);
+        if (flagIndex != -1) {
+            int flags = 0;
+            if (file.canWrite()) {
+                if (mimeType.equals(Document.MIME_TYPE_DIR)) {
+                    flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+                    flags |= Document.FLAG_SUPPORTS_DELETE;
+                    flags |= Document.FLAG_SUPPORTS_RENAME;
+                    flags |= Document.FLAG_SUPPORTS_MOVE;
+                } else {
+                    flags |= Document.FLAG_SUPPORTS_WRITE;
+                    flags |= Document.FLAG_SUPPORTS_DELETE;
+                    flags |= Document.FLAG_SUPPORTS_RENAME;
+                    flags |= Document.FLAG_SUPPORTS_MOVE;
+                }
+            }
 
-        if (file.canWrite()) {
-            if (file.isDirectory()) {
-                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
-                flags |= Document.FLAG_SUPPORTS_DELETE;
-                flags |= Document.FLAG_SUPPORTS_RENAME;
-                flags |= Document.FLAG_SUPPORTS_MOVE;
-            } else {
-                flags |= Document.FLAG_SUPPORTS_WRITE;
-                flags |= Document.FLAG_SUPPORTS_DELETE;
-                flags |= Document.FLAG_SUPPORTS_RENAME;
-                flags |= Document.FLAG_SUPPORTS_MOVE;
+            if (mimeType.startsWith("image/")) {
+                flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+            }
+
+            if (typeSupportsMetadata(mimeType)) {
+                flags |= Document.FLAG_SUPPORTS_METADATA;
+            }
+            row.add(flagIndex, flags);
+        }
+
+        final int displayNameIndex = ArrayUtils.indexOf(columns, Document.COLUMN_DISPLAY_NAME);
+        if (displayNameIndex != -1) {
+            row.add(displayNameIndex, file.getName());
+        }
+
+        final int lastModifiedIndex = ArrayUtils.indexOf(columns, Document.COLUMN_LAST_MODIFIED);
+        if (lastModifiedIndex != -1) {
+            final long lastModified = file.lastModified();
+            // Only publish dates reasonably after epoch
+            if (lastModified > 31536000000L) {
+                row.add(lastModifiedIndex, lastModified);
             }
         }
-
-        final String mimeType = getDocumentType(docId);
-        final String displayName = file.getName();
-        if (mimeType.startsWith("image/")) {
-            flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
-        }
-
-        if (typeSupportsMetadata(mimeType)) {
-            flags |= Document.FLAG_SUPPORTS_METADATA;
-        }
-
-        final RowBuilder row = result.newRow();
-        row.add(Document.COLUMN_DOCUMENT_ID, docId);
-        row.add(Document.COLUMN_DISPLAY_NAME, displayName);
-        row.add(Document.COLUMN_SIZE, file.length());
-        row.add(Document.COLUMN_MIME_TYPE, mimeType);
-        row.add(Document.COLUMN_FLAGS, flags);
-
-        // Only publish dates reasonably after epoch
-        long lastModified = file.lastModified();
-        if (lastModified > 31536000000L) {
-            row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
+        final int sizeIndex = ArrayUtils.indexOf(columns, Document.COLUMN_SIZE);
+        if (sizeIndex != -1) {
+            row.add(sizeIndex, file.length());
         }
 
         // Return the row builder just in case any subclass want to add more stuff to it.
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 1ff7418..9cffb2b 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2354,4 +2354,11 @@
 
     // OPEN: Settings > Pick preferred SIM dialog
     DIALOG_PREFERRED_SIM_PICKER = 1709;
+
+    // OPEN: Settings > Network & internet > Mobile network > Delete sim
+    DIALOG_DELETE_SIM_CONFIRMATION = 1713;
+
+    // OPEN: Settings >  Network & internet > Mobile network > Delete sim > (answer yes to
+    //       confirmation)
+    DIALOG_DELETE_SIM_PROGRESS = 1714;
 }
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b47097d..8f16b41 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -501,7 +501,10 @@
     }
     optional IntentFirewall intent_firewall = 65;
 
-    optional SettingProto job_scheduler_constants = 66;
+    optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto job_scheduler_time_controller_constants = 150 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message LangId {
@@ -1049,5 +1052,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 149;
+    // Next tag = 151;
 }
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 8727f4c..17b5f50 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -37,8 +37,8 @@
             android:layout_width="24dp"
             android:layout_height="4dp"
             android:src="@drawable/ic_drag_handle"
-            android:clickable="true"
             android:layout_marginTop="@dimen/chooser_edge_margin_thin"
+            android:layout_marginBottom="@dimen/chooser_edge_margin_thin"
             android:tint="@color/lighter_gray"
             android:layout_centerHorizontal="true"
             android:layout_alignParentTop="true" />
@@ -46,11 +46,8 @@
         <TextView android:id="@+id/title"
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
-                  android:textAppearance="?attr/textAppearanceMedium"
-                  android:textSize="20sp"
-                  android:textColor="?attr/textColorPrimary"
+                  android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
                   android:gravity="center"
-                  android:paddingTop="@dimen/chooser_edge_margin_thin"
                   android:paddingBottom="@dimen/chooser_view_spacing"
                   android:paddingLeft="24dp"
                   android:paddingRight="24dp"
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index f3ca0af..e889e85 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -44,6 +44,7 @@
         android:layout_toStartOf="@id/copy_button"
         android:layout_centerVertical="true"
         android:ellipsize="end"
+        android:fontFamily="@android:string/config_headlineFontFamily"
         android:textColor="?android:attr/textColorPrimary"
         android:maxLines="2"/>
 
@@ -112,8 +113,8 @@
         android:layout_gravity="center_vertical"
         android:ellipsize="end"
         android:maxLines="2"
-        android:textSize="20sp"
-        android:textColor="?android:attr/textColorPrimary"/>
+        android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
+        android:fontFamily="@android:string/config_headlineFontFamily"/>
   </LinearLayout>
 </LinearLayout>
 
diff --git a/core/res/res/layout/chooser_profile_row.xml b/core/res/res/layout/chooser_profile_row.xml
index 1a24a07..fe4f949 100644
--- a/core/res/res/layout/chooser_profile_row.xml
+++ b/core/res/res/layout/chooser_profile_row.xml
@@ -20,7 +20,7 @@
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:gravity="center">
-  <TextView
+  <Button
       android:id="@+id/profile_button"
       android:layout_width="wrap_content"
       android:layout_height="48dp"
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f4d3c81..61fb811 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -294,6 +294,8 @@
                     Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
                     Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
                     Settings.Global.JOB_SCHEDULER_CONSTANTS,
+                    Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
+                    Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS,
                     Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
                     Settings.Global.KERNEL_CPU_THREAD_READER,
                     Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index 46288bb..296db46 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -102,10 +102,10 @@
     }
 
     private void registerDeviceConfigs() {
-        DeviceConfig.addOnPropertyChangedListener(
+        DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 this::postToHandler,
-                this::onDeviceConfigPropertyChanged);
+                (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
 
         // Update the fields in this class from the current state of the device config.
         updateFromDeviceConfigFlags();
@@ -116,10 +116,10 @@
     }
 
     @VisibleForTesting
-    void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
+    void onDeviceConfigPropertiesChanged(String namespace) {
         if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
             Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: "
-                    + namespace + " " + name + "=" + value);
+                    + namespace);
             return;
         }
 
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index ad52e2b..5c877de 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -96,10 +96,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
                 "false",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                "false");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertFalse(mAssistantSettings.mGenerateReplies);
     }
@@ -111,10 +108,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
                 "true",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                "true");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertTrue(mAssistantSettings.mGenerateReplies);
     }
@@ -126,10 +120,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
                 "false",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                "false");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertFalse(mAssistantSettings.mGenerateReplies);
 
@@ -138,10 +129,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
                 null,
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                null);
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         // Go back to the default value.
         assertTrue(mAssistantSettings.mGenerateReplies);
@@ -154,10 +142,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
                 "false",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                "false");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertFalse(mAssistantSettings.mGenerateActions);
     }
@@ -169,10 +154,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
                 "true",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                "true");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertTrue(mAssistantSettings.mGenerateActions);
     }
@@ -184,10 +166,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
                 "false",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                "false");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertFalse(mAssistantSettings.mGenerateActions);
 
@@ -196,10 +175,7 @@
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
                 null,
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                null);
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         // Go back to the default value.
         assertTrue(mAssistantSettings.mGenerateActions);
@@ -212,10 +188,7 @@
                 SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
                 "10",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
-                "10");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertEquals(10, mAssistantSettings.mMaxMessagesToExtract);
     }
@@ -227,20 +200,14 @@
                 SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
                 "5",
                 false /* makeDefault */));
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
-                "5");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertEquals(5, mAssistantSettings.mMaxSuggestions);
     }
 
     @Test
     public void testMaxSuggestionsEmpty() {
-        mAssistantSettings.onDeviceConfigPropertyChanged(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
-                "");
+        mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
 
         assertEquals(DEFAULT_MAX_SUGGESTIONS, mAssistantSettings.mMaxSuggestions);
     }
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index e0bb862..62de2ba 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -56,15 +56,24 @@
     srcs: [
         "jni/network_stack_utils_jni.cpp"
     ],
-
+    sdk_version: "current",
     shared_libs: [
         "liblog",
-        "libcutils",
-        "libnativehelper",
+        "libnativehelper_compat_libc++",
     ],
-    static_libs: [
-        "libpcap",
-    ],
+
+    // We cannot use plain "libc++" here to link libc++ dynamically because it results in:
+    //   java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
+    // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't
+    // build because soong complains of:
+    //   module NetworkStack missing dependencies: libc++_shared
+    //
+    // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries
+    // we depend on do not dynamically link libc++. This is currently the case, because liblog is
+    // C-only and libnativehelper_compat_libc also uses stl: "c++_static".
+    //
+    // TODO: find a better solution for this in R.
+    stl: "c++_static",
     cflags: [
         "-Wall",
         "-Werror",
@@ -79,7 +88,10 @@
     static_libs: [
         "NetworkStackBase",
     ],
-    jni_libs: ["libnetworkstackutilsjni"],
+    jni_libs: [
+        "libnativehelper_compat_libc++",
+        "libnetworkstackutilsjni",
+    ],
     // Resources already included in NetworkStackBase
     resource_dirs: [],
     jarjar_rules: "jarjar-rules-shared.txt",
diff --git a/packages/NetworkStack/jni/network_stack_utils_jni.cpp b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
index 5544eaa..f2ba575 100644
--- a/packages/NetworkStack/jni/network_stack_utils_jni.cpp
+++ b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
@@ -31,7 +31,7 @@
 #include <string>
 
 #include <nativehelper/JNIHelp.h>
-#include <utils/Log.h>
+#include <android/log.h>
 
 namespace android {
 constexpr const char NETWORKSTACKUTILS_PKG_NAME[] = "android/net/util/NetworkStackUtils";
@@ -249,7 +249,7 @@
 extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
     JNIEnv *env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed");
+        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
         return JNI_ERR;
     }
 
@@ -261,4 +261,4 @@
     return JNI_VERSION_1_6;
 
 }
-}; // namespace android
\ No newline at end of file
+}; // namespace android
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index fe3c1e8..039f6bf 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -56,6 +56,7 @@
         "liblog",
         "liblzma",
         "libnativehelper",
+        "libnativehelper_compat_libc++",
         "libnetworkstacktestsjni",
         "libnetworkstackutilsjni",
         "libpackagelistparser",
@@ -99,5 +100,4 @@
         "libapf",
         "libpcap",
     ],
-
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index cd4f6cf..c94ee0e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -797,6 +797,12 @@
                 Settings.Global.JOB_SCHEDULER_CONSTANTS,
                 GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
         dumpSetting(s, p,
+                Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
+                GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS,
+                GlobalSettingsProto.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS);
+        dumpSetting(s, p,
                 Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
                 GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND);
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 66d5d11..25a3fa2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.view.View;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
@@ -32,13 +33,20 @@
     void startPendingIntentDismissingKeyguard(PendingIntent intent);
 
     /**
-     * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but allows
+     * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent)}, but allows
      * you to specify the callback that is executed on the UI thread after the intent is sent.
      */
     void startPendingIntentDismissingKeyguard(PendingIntent intent,
             Runnable intentSentUiThreadCallback);
 
     /**
+     * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but also
+     * specifies an associated view that should be used for the activity launch animation.
+     */
+    void startPendingIntentDismissingKeyguard(PendingIntent intent,
+            Runnable intentSentUiThreadCallback, View associatedView);
+
+    /**
      * The intent flag can be specified in startActivity().
      */
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index 8f74806..8dd06f0 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -42,6 +42,7 @@
         android:layout_weight="1"
         android:textAppearance="@style/TextAppearance.QS.Status"
         android:textDirection="locale"
+        android:marqueeRepeatLimit="marquee_forever"
         android:singleLine="true"
         android:maxEms="7"/>
 
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 04f887b..41a7bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -16,6 +16,7 @@
 
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.view.View;
 
 import com.android.systemui.plugins.ActivityStarter;
 
@@ -53,6 +54,16 @@
     }
 
     @Override
+    public void startPendingIntentDismissingKeyguard(PendingIntent intent,
+            Runnable intentSentCallback, View associatedView) {
+        if (mActualStarter == null) {
+            return;
+        }
+        mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback,
+                associatedView);
+    }
+
+    @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
             int flags) {
         if (mActualStarter == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index fa22367..1615e65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -39,6 +39,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
 import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
@@ -118,15 +119,18 @@
     private ImageView mBackdropBack;
 
     private boolean mShowCompactMediaSeekbar;
-    private final DeviceConfig.OnPropertyChangedListener mPropertyChangedListener =
-            new DeviceConfig.OnPropertyChangedListener() {
+    private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
         @Override
-        public void onPropertyChanged(String namespace, String name, String value) {
-            if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
-                if (DEBUG_MEDIA) {
-                    Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
+        public void onPropertiesChanged(Properties properties) {
+            for (String name : properties.getKeyset()) {
+                if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
+                    String value = properties.getString(name, null);
+                    if (DEBUG_MEDIA) {
+                        Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
+                    }
+                    mShowCompactMediaSeekbar = "true".equals(value);
                 }
-                mShowCompactMediaSeekbar = "true".equals(value);
             }
         }
     };
@@ -189,9 +193,9 @@
                 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
 
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                 mContext.getMainExecutor(),
-                mPropertyChangedListener);
+                mPropertiesChangedListener);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 333239e..0d9f4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -30,6 +30,7 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.View;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.systemui.Interpolators;
@@ -79,11 +80,12 @@
     }
 
     public RemoteAnimationAdapter getLaunchAnimation(
-            ExpandableNotificationRow sourceNotification, boolean occluded) {
-        if (!mCallback.areLaunchAnimationsEnabled() || occluded) {
+            View sourceView, boolean occluded) {
+        if (!(sourceView instanceof ExpandableNotificationRow) || !mCallback.areLaunchAnimationsEnabled() || occluded) {
             return null;
         }
-        AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
+        AnimationRunner animationRunner = new AnimationRunner(
+                (ExpandableNotificationRow) sourceView);
         return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
                 ANIMATION_DURATION - 150 /* statusBarTransitionDelay */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index ef7d20c..73f7732 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -42,7 +42,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
@@ -80,7 +79,7 @@
     private OnMenuEventListener mMenuListener;
     private boolean mDismissRtl;
     private boolean mIsForeground;
-    private final boolean mIsUsingNewInterruptionModel;
+    private final boolean mIsUsingBidirectionalSwipe;
 
     private ValueAnimator mFadeAnimator;
     private boolean mAnimating;
@@ -113,12 +112,19 @@
     private boolean mIsUserTouching;
 
     public NotificationMenuRow(Context context) {
+        //TODO: (b/131242807) not using bidirectional swipe for now
+        this(context, false);
+    }
+
+    // Only needed for testing until we want to turn bidirectional swipe back on
+    @VisibleForTesting
+    NotificationMenuRow(Context context, boolean isUsingBidirectionalSwipe) {
         mContext = context;
         mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear);
         mHandler = new Handler(Looper.getMainLooper());
         mLeftMenuItems = new ArrayList<>();
         mRightMenuItems = new ArrayList<>();
-        mIsUsingNewInterruptionModel = NotificationUtils.useNewInterruptionModel(mContext);
+        mIsUsingBidirectionalSwipe = isUsingBidirectionalSwipe;
     }
 
     @Override
@@ -255,13 +261,13 @@
             mSnoozeItem = createSnoozeItem(mContext);
         }
         mAppOpsItem = createAppOpsItem(mContext);
-        if (mIsUsingNewInterruptionModel) {
+        if (mIsUsingBidirectionalSwipe) {
             mInfoItem = createInfoItem(mContext, !mParent.getEntry().isHighPriority());
         } else {
             mInfoItem = createInfoItem(mContext);
         }
 
-        if (!mIsUsingNewInterruptionModel) {
+        if (!mIsUsingBidirectionalSwipe) {
             if (!isForeground) {
                 mRightMenuItems.add(mSnoozeItem);
             }
@@ -618,12 +624,12 @@
 
     @Override
     public boolean shouldShowGutsOnSnapOpen() {
-        return mIsUsingNewInterruptionModel;
+        return mIsUsingBidirectionalSwipe;
     }
 
     @Override
     public MenuItem menuItemToExposeOnSnap() {
-        return mIsUsingNewInterruptionModel ? mInfoItem : null;
+        return mIsUsingBidirectionalSwipe ? mInfoItem : null;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ebda585..7a9da6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6355,13 +6355,8 @@
 
         @Override
         public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
-            boolean isValidDirection;
-            if (NotificationUtils.useNewInterruptionModel(mContext)) {
-                isValidDirection = mDismissRtl ? !isRightOrDown : isRightOrDown;
-            } else {
-                isValidDirection = true;
-            }
-            return isValidDirection && canChildBeDismissed(v);
+            //TODO: b/131242807 for why this doesn't do anything with direction
+            return canChildBeDismissed(v);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d5706e3..27368de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,6 +44,7 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.privacy.PrivacyItem;
 import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.statusbar.CommandQueue;
@@ -229,9 +230,11 @@
         mIconController.setIconVisibility(mSlotDataSaver, false);
 
         // privacy items
-        mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null);
+        mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none,
+                PrivacyType.TYPE_MICROPHONE.getName(mContext));
         mIconController.setIconVisibility(mSlotMicrophone, false);
-        mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null);
+        mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera,
+                PrivacyType.TYPE_CAMERA.getName(mContext));
         mIconController.setIconVisibility(mSlotCamera, false);
         mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
                 mContext.getString(R.string.accessibility_location_active));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 93db82d..739343a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -593,6 +593,7 @@
                 updateScrimController();
             };
     private ActivityIntentHelper mActivityIntentHelper;
+    private ShadeController mShadeController;
 
     @Override
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -1062,7 +1063,7 @@
         final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
                 (StatusBarRemoteInputCallback) Dependency.get(
                         NotificationRemoteInputManager.Callback.class);
-        final ShadeController shadeController = Dependency.get(ShadeController.class);
+        mShadeController = Dependency.get(ShadeController.class);
         final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
 
         mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
@@ -1070,7 +1071,7 @@
                 mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
                 mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
                 mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
-                mLockscreenUserManager, shadeController, mKeyguardMonitor,
+                mLockscreenUserManager, mShadeController, mKeyguardMonitor,
                 mNotificationInterruptionStateProvider, mMetricsLogger,
                 new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER),
                 Dependency.get(BG_HANDLER), mActivityIntentHelper, mBubbleController);
@@ -4344,6 +4345,13 @@
     @Override
     public void startPendingIntentDismissingKeyguard(
             final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
+        startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback, null /* row */);
+    }
+
+    @Override
+    public void startPendingIntentDismissingKeyguard(
+            final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback,
+            View associatedView) {
         final boolean afterKeyguardGone = intent.isActivity()
                 && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
@@ -4351,7 +4359,8 @@
         executeActionDismissingKeyguard(() -> {
             try {
                 intent.send(null, 0, null, null, null, null, getActivityOptions(
-                        null /* animationAdapter */));
+                        mActivityLaunchAnimator.getLaunchAnimation(associatedView,
+                                mShadeController.isOccluded())));
             } catch (PendingIntent.CanceledException e) {
                 // the stack trace isn't very helpful here.
                 // Just log the exception message.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index f02b544..655c29c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -93,10 +93,10 @@
     }
 
     private void registerDeviceConfigListener() {
-        DeviceConfig.addOnPropertyChangedListener(
+        DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 this::postToHandler,
-                this::onDeviceConfigPropertyChanged);
+                (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
     }
 
     private void postToHandler(Runnable r) {
@@ -104,10 +104,10 @@
     }
 
     @VisibleForTesting
-    void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
+    void onDeviceConfigPropertiesChanged(String namespace) {
         if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
             Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: "
-                    + namespace + " " + name + "=" + value);
+                    + namespace);
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 0f7a0f0..640f0f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -349,7 +349,7 @@
                             smartReplyController.smartActionClicked(
                                     entry, actionIndex, action, smartActions.fromAssistant);
                             headsUpManager.removeNotification(entry.key, true);
-                        });
+                        }, entry.getRow());
         if (useDelayedOnClickListener) {
             onClickListener = new DelayedOnClickListener(onClickListener,
                     smartReplyView.mConstants.getOnClickInitDelay());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 212c8f5..e312990 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -189,10 +189,6 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -217,10 +213,6 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -243,11 +235,6 @@
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
-                new ArrayList<>());
-
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
                 ArgumentCaptor.forClass(
                         CarrierTextController.CarrierTextCallbackInfo.class);
@@ -271,10 +258,6 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -300,10 +283,6 @@
                 .thenReturn(IccCardConstants.State.NOT_READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -329,10 +308,6 @@
                 .thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -361,10 +336,6 @@
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
                 ArgumentCaptor.forClass(
                         CarrierTextController.CarrierTextCallbackInfo.class);
@@ -385,12 +356,9 @@
         list.add(TEST_SUBSCRIPTION_2);
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
             .thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
         mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText();
-
-        // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
-        // same answer as KeyguardUpdateMonitor. Remove when this is addressed
         when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index c62a802..43ea92f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -112,11 +112,8 @@
     }
 
     @Test
-    public void testNoAppOpsInSlowSwipe_newInterruptionModel() {
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
-
-        NotificationMenuRow row = new NotificationMenuRow(mContext);
+    public void testNoAppOpsInSlowSwipe_biDirectionalSwipe() {
+        NotificationMenuRow row = new NotificationMenuRow(mContext, true);
         row.createMenu(mRow, null);
 
         ViewGroup container = (ViewGroup) row.getMenuView();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index fb2b7dc..c761a44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -229,8 +229,7 @@
     }
 
     private void triggerConstantsOnChange() {
-        mConstants.onDeviceConfigPropertyChanged(DeviceConfig.NAMESPACE_SYSTEMUI,
-                "" /* name */, "" /* value */);
+        mConstants.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
     }
 
     private void resetAllDeviceConfigFlags() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 01f3c92..8c5fac4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -634,7 +634,8 @@
 
         mView.getChildAt(2).performClick();
 
-        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+                any());
     }
 
     @Test
@@ -645,7 +646,7 @@
 
         mView.getChildAt(2).performClick();
 
-        verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any());
+        verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any(), any());
     }
 
     @Test
@@ -657,7 +658,8 @@
         Thread.sleep(delayMs);
         mView.getChildAt(2).performClick();
 
-        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+                any());
     }
 
     @Test
@@ -668,7 +670,8 @@
 
         mView.getChildAt(2).performClick();
 
-        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+        verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+                any());
     }
 
     @Test
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 21c6035..fe92d45 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7206,6 +7206,13 @@
     // ACTION: Share Wi-Fi hotspot by generating a QR code
     ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE = 1712;
 
+    // OPEN: Settings > Network & internet > Mobile network > Delete sim
+    DIALOG_DELETE_SIM_CONFIRMATION = 1713;
+
+    // OPEN: Settings >  Network & internet > Mobile network > Delete sim > (answer yes to
+    //       confirmation)
+    DIALOG_DELETE_SIM_PROGRESS = 1714;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a94d1dc..a64f4e4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -94,6 +94,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Entry point service for autofill management.
@@ -192,9 +193,9 @@
         mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
         mAm = LocalServices.getService(ActivityManagerInternal.class);
 
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
                 ActivityThread.currentApplication().getMainExecutor(),
-                (namespace, key, value) -> onDeviceConfigChange(key));
+                (properties) -> onDeviceConfigChange(properties.getKeyset()));
 
         setLogLevelFromSettings();
         setMaxPartitionsFromSettings();
@@ -270,15 +271,17 @@
         }
     }
 
-    private void onDeviceConfigChange(@NonNull String key) {
-        switch (key) {
-            case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
-            case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
-            case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
-                setDeviceConfigProperties();
-                break;
-            default:
-                Slog.i(mTag, "Ignoring change on " + key);
+    private void onDeviceConfigChange(@NonNull Set<String> keys) {
+        for (String key : keys) {
+            switch (key) {
+                case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
+                case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
+                case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+                    setDeviceConfigProperties();
+                    break;
+                default:
+                    Slog.i(mTag, "Ignoring change on " + key);
+            }
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index f1963b3..386dec4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -57,6 +57,7 @@
 import android.service.autofill.FillEventHistory.Event;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
+import android.service.autofill.SaveInfo;
 import android.service.autofill.UserData;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -595,8 +596,8 @@
         ArrayList<Session> previousSessions = null;
         for (int i = 0; i < size; i++) {
             final Session previousSession = mSessions.valueAt(i);
-            // TODO(b/113281366): only return sessions asked to be kept alive / add CTS test
-            if (previousSession.taskId == session.taskId && previousSession.id != session.id) {
+            if (previousSession.taskId == session.taskId && previousSession.id != session.id
+                    && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
                 if (previousSessions == null) {
                     previousSessions = new ArrayList<>(size);
                 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 9eda9db..7b97353 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1203,9 +1203,12 @@
 
     @GuardedBy("mLock")
     @Nullable
-    private FillResponse getLastResponseLocked(@Nullable String logPrefix) {
+    private FillResponse getLastResponseLocked(@Nullable String logPrefixFmt) {
+        final String logPrefix = sDebug && logPrefixFmt != null
+                ? String.format(logPrefixFmt, this.id)
+                : null;
         if (mContexts == null) {
-            if (sDebug && logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
+            if (logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
             return null;
         }
         if (mResponses == null) {
@@ -1241,6 +1244,12 @@
         return response == null ? null : response.getSaveInfo();
     }
 
+    @GuardedBy("mLock")
+    int getSaveInfoFlagsLocked() {
+        final SaveInfo saveInfo = getSaveInfoLocked();
+        return saveInfo == null ? 0 : saveInfo.getFlags();
+    }
+
     /**
      * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}
      * when necessary.
@@ -1252,7 +1261,7 @@
     private void handleLogContextCommitted() {
         final FillResponse lastResponse;
         synchronized (mLock) {
-            lastResponse = getLastResponseLocked("logContextCommited()");
+            lastResponse = getLastResponseLocked("logContextCommited(%s)");
         }
 
         if (lastResponse == null) {
@@ -1295,7 +1304,7 @@
     @GuardedBy("mLock")
     private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
             @Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
-        final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
+        final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)");
         if (lastResponse == null) return;
 
         final int flags = lastResponse.getFlags();
@@ -1610,7 +1619,7 @@
                     + id + " destroyed");
             return false;
         }
-        final FillResponse response = getLastResponseLocked("showSaveLocked()");
+        final FillResponse response = getLastResponseLocked("showSaveLocked(%s)");
         final SaveInfo saveInfo = response == null ? null : response.getSaveInfo();
 
         /*
@@ -1624,13 +1633,13 @@
          * - server didn't ask to keep session alive
          */
         if (saveInfo == null) {
-            if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service");
+            if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service");
             return true;
         }
 
         if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
             // TODO(b/113281366): log metrics
-            if (sDebug) Slog.v(TAG, "showSaveLocked(): service asked to delay save");
+            if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save");
             return false;
         }
 
@@ -1962,7 +1971,8 @@
             if (node != null) {
                 final AutofillValue value = node.getAutofillValue();
                 if (sDebug) {
-                    Slog.d(TAG, "getValueFromContexts(" + autofillId + ") at " + i + ": " + value);
+                    Slog.d(TAG, "getValueFromContexts(" + this.id + "/" + autofillId + ") at "
+                            + i + ": " + value);
                 }
                 if (value != null && !value.isEmpty()) {
                     return value;
@@ -2066,7 +2076,7 @@
             return;
         }
 
-        if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
+        if (sVerbose) Slog.v(TAG, "callSaveLocked(" + this.id + "): mViewStates=" + mViewStates);
 
         if (mContexts == null) {
             Slog.w(TAG, "callSaveLocked(): no contexts");
@@ -2109,15 +2119,15 @@
         final ArrayList<FillContext> contexts;
         if (previousSessions != null) {
             if (sDebug) {
-                Slog.d(TAG, "mergeSessions(): Merging the content of " + previousSessions.size()
-                        + " sessions for task " + taskId);
+                Slog.d(TAG, "mergeSessions(" + this.id + "): Merging the content of "
+                        + previousSessions.size() + " sessions for task " + taskId);
             }
             contexts = new ArrayList<>();
             for (int i = 0; i < previousSessions.size(); i++) {
                 final Session previousSession = previousSessions.get(i);
                 final ArrayList<FillContext> previousContexts = previousSession.mContexts;
                 if (previousContexts == null) {
-                    Slog.w(TAG, "mergeSessions(): Not merging null contexts from "
+                    Slog.w(TAG, "mergeSessions(" + this.id + "): Not merging null contexts from "
                             + previousSession.id);
                     continue;
                 }
@@ -2125,14 +2135,14 @@
                     previousSession.updateValuesForSaveLocked();
                 }
                 if (sDebug) {
-                    Slog.d(TAG, "mergeSessions(): adding " + previousContexts.size()
+                    Slog.d(TAG, "mergeSessions(" + this.id + "): adding " + previousContexts.size()
                             + " context from previous session #" + previousSession.id);
                 }
                 contexts.addAll(previousContexts);
                 if (mClientState == null && previousSession.mClientState != null) {
                     if (sDebug) {
-                        Slog.d(TAG, "mergeSessions(): setting client state from previous session"
-                                + previousSession.id);
+                        Slog.d(TAG, "mergeSessions(" + this.id + "): setting client state from "
+                                + "previous session" + previousSession.id);
                     }
                     mClientState = previousSession.mClientState;
                 }
@@ -2250,8 +2260,8 @@
             return;
         }
         if (sVerbose) {
-            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + actionAsString(action)
-                    + ", flags=" + flags);
+            Slog.v(TAG, "updateLocked(" + this.id + "): id=" + id + ", action="
+                    + actionAsString(action) + ", flags=" + flags);
         }
         ViewState viewState = mViewStates.get(id);
 
@@ -3291,7 +3301,7 @@
      */
     @GuardedBy("mLock")
     void removeSelfLocked() {
-        if (sVerbose) Slog.v(TAG, "removeSelfLocked(): " + mPendingSaveUi);
+        if (sVerbose) Slog.v(TAG, "removeSelfLocked(" + this.id + "): " + mPendingSaveUi);
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
                     + id + " destroyed");
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 33a2e50..e1b089c 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -214,7 +214,7 @@
         if (mDatasetId != null) {
             builder.append(", datasetId:" ).append(mDatasetId);
         }
-        builder.append("state:" ).append(getStateAsString());
+        builder.append(", state:").append(getStateAsString());
         if (mCurrentValue != null) {
             builder.append(", currentValue:" ).append(mCurrentValue);
         }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index a2d3d4c..5c6258f 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -50,6 +50,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
 import android.provider.Settings;
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.util.ArraySet;
@@ -131,9 +132,9 @@
                 com.android.internal.R.string.config_defaultContentCaptureService),
                 UserManager.DISALLOW_CONTENT_CAPTURE,
                 /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
-                (namespace, key, value) -> onDeviceConfigChange(key, value));
+                (properties) -> onDeviceConfigChange(properties));
         setDeviceConfigProperties();
 
         if (mDevCfgLogHistorySize > 0) {
@@ -255,23 +256,25 @@
         return enabled;
     }
 
-    private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
-        switch (key) {
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
-                setDisabledByDeviceConfig(value);
-                return;
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
-                setLoggingLevelFromDeviceConfig();
-                return;
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
-            case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
-                setFineTuneParamsFromDeviceConfig();
-                return;
-            default:
-                Slog.i(mTag, "Ignoring change on " + key);
+    private void onDeviceConfigChange(@NonNull Properties properties) {
+        for (String key : properties.getKeyset()) {
+            switch (key) {
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
+                    setDisabledByDeviceConfig(properties.getString(key, null));
+                    return;
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
+                    setLoggingLevelFromDeviceConfig();
+                    return;
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
+                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
+                    setFineTuneParamsFromDeviceConfig();
+                    return;
+                default:
+                    Slog.i(mTag, "Ignoring change on " + key);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b44009f..7b5b419 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.provider.DeviceConfig;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -61,6 +62,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Monitors the health of packages on the system and notifies interested observers when packages
@@ -69,10 +71,22 @@
  */
 public class PackageWatchdog {
     private static final String TAG = "PackageWatchdog";
+
+    static final String PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS =
+            "watchdog_trigger_failure_duration_millis";
+    static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT =
+            "watchdog_trigger_failure_count";
+    static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED =
+            "watchdog_explicit_health_check_enabled";
+
     // Duration to count package failures before it resets to 0
-    private static final int TRIGGER_DURATION_MS = 60000;
+    private static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS =
+            (int) TimeUnit.MINUTES.toMillis(1);
     // Number of package failures within the duration above before we notify observers
-    static final int TRIGGER_FAILURE_COUNT = 5;
+    private static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5;
+    // Whether explicit health checks are enabled or not
+    private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
+
     private static final int DB_VERSION = 1;
     private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
     private static final String TAG_PACKAGE = "package";
@@ -83,6 +97,7 @@
     private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
     private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
 
+    @GuardedBy("PackageWatchdog.class")
     private static PackageWatchdog sPackageWatchdog;
 
     private final Object mLock = new Object();
@@ -100,11 +115,15 @@
     // File containing the XML data of monitored packages /data/system/package-watchdog.xml
     private final AtomicFile mPolicyFile;
     private final ExplicitHealthCheckController mHealthCheckController;
-    // Flag to control whether explicit health checks are supported or not
-    @GuardedBy("mLock")
-    private boolean mIsHealthCheckEnabled = true;
     @GuardedBy("mLock")
     private boolean mIsPackagesReady;
+    // Flag to control whether explicit health checks are supported or not
+    @GuardedBy("mLock")
+    private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED;
+    @GuardedBy("mLock")
+    private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
+    @GuardedBy("mLock")
+    private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
     // SystemClock#uptimeMillis when we last executed #syncState
     // 0 if no prune is scheduled.
     @GuardedBy("mLock")
@@ -153,8 +172,8 @@
             mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
                     packages -> onSupportedPackages(packages),
                     () -> syncRequestsAsync());
-            // Controller is initially disabled until here where we may enable it and sync our state
-            setExplicitHealthCheckEnabled(mIsHealthCheckEnabled);
+            setPropertyChangedListenerLocked();
+            updateConfigs();
         }
     }
 
@@ -332,14 +351,13 @@
         }
     }
 
-    // TODO(b/120598832): Set depending on DeviceConfig flag
     /**
      * Enables or disables explicit health checks.
      * <p> If explicit health checks are enabled, the health check service is started.
      * <p> If explicit health checks are disabled, pending explicit health check requests are
      * passed and the health check service is stopped.
      */
-    public void setExplicitHealthCheckEnabled(boolean enabled) {
+    private void setExplicitHealthCheckEnabled(boolean enabled) {
         synchronized (mLock) {
             mIsHealthCheckEnabled = enabled;
             mHealthCheckController.setEnabled(enabled);
@@ -390,6 +408,12 @@
         String getName();
     }
 
+    long getTriggerFailureCount() {
+        synchronized (mLock) {
+            return mTriggerFailureCount;
+        }
+    }
+
     /**
      * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
      */
@@ -646,7 +670,7 @@
             XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-                ObserverInternal observer = ObserverInternal.read(parser);
+                ObserverInternal observer = ObserverInternal.read(parser, this);
                 if (observer != null) {
                     mAllObservers.put(observer.mName, observer);
                 }
@@ -661,6 +685,48 @@
         }
     }
 
+    /** Adds a {@link DeviceConfig#OnPropertyChangedListener}. */
+    private void setPropertyChangedListenerLocked() {
+        DeviceConfig.addOnPropertyChangedListener(
+                DeviceConfig.NAMESPACE_ROLLBACK,
+                mContext.getMainExecutor(),
+                (namespace, name, value) -> {
+                    if (!DeviceConfig.NAMESPACE_ROLLBACK.equals(namespace)) {
+                        return;
+                    }
+                    updateConfigs();
+                });
+    }
+
+    /**
+     * Health check is enabled or disabled after reading the flags
+     * from DeviceConfig.
+     */
+    private void updateConfigs() {
+        synchronized (mLock) {
+            mTriggerFailureCount = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+                    DEFAULT_TRIGGER_FAILURE_COUNT);
+            if (mTriggerFailureCount <= 0) {
+                mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
+            }
+
+            mTriggerFailureDurationMs = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+                    DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+            if (mTriggerFailureDurationMs <= 0) {
+                mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_COUNT;
+            }
+
+            setExplicitHealthCheckEnabled(DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+                    DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED));
+        }
+    }
+
     /**
      * Persists mAllObservers to file. Threshold information is ignored.
      */
@@ -805,7 +871,7 @@
          * #loadFromFile which in turn is only called on construction of the
          * singleton PackageWatchdog.
          **/
-        public static ObserverInternal read(XmlPullParser parser) {
+        public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) {
             String observerName = null;
             if (TAG_OBSERVER.equals(parser.getName())) {
                 observerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -829,7 +895,7 @@
                             boolean hasPassedHealthCheck = Boolean.parseBoolean(
                                     parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
                             if (!TextUtils.isEmpty(packageName)) {
-                                packages.add(new MonitoredPackage(packageName, duration,
+                                packages.add(watchdog.new MonitoredPackage(packageName, duration,
                                         healthCheckDuration, hasPassedHealthCheck));
                             }
                         } catch (NumberFormatException e) {
@@ -856,7 +922,7 @@
      * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
      * instances of this class.
      */
-    static class MonitoredPackage {
+    class MonitoredPackage {
         // Health check states
         // TODO(b/120598832): Prefix with HEALTH_CHECK
         // mName has not passed health check but has requested a health check
@@ -931,7 +997,7 @@
         public boolean onFailureLocked() {
             final long now = SystemClock.uptimeMillis();
             final long duration = now - mUptimeStartMs;
-            if (duration > TRIGGER_DURATION_MS) {
+            if (duration > mTriggerFailureDurationMs) {
                 // TODO(b/120598832): Reseting to 1 is not correct
                 // because there may be more than 1 failure in the last trigger window from now
                 // This is the RescueParty impl, will leave for now
@@ -940,7 +1006,7 @@
             } else {
                 mFailures++;
             }
-            boolean failed = mFailures >= TRIGGER_FAILURE_COUNT;
+            boolean failed = mFailures >= mTriggerFailureCount;
             if (failed) {
                 mFailures = 0;
             }
@@ -1065,7 +1131,7 @@
         }
 
         /** Returns a {@link String} representation of the current health check state. */
-        private static String toString(int state) {
+        private String toString(int state) {
             switch (state) {
                 case STATE_ACTIVE:
                     return "ACTIVE";
@@ -1081,7 +1147,7 @@
         }
 
         /** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */
-        private static long toPositive(long value) {
+        private long toPositive(long value) {
             return value > 0 ? value : Long.MAX_VALUE;
         }
     }
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 1fe0271..fb1a962 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -72,8 +72,12 @@
     static final int LEVEL_FACTORY_RESET = 4;
     @VisibleForTesting
     static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
+    /**
+     * The boot trigger window size must always be greater than Watchdog's deadlock timeout
+     * {@link Watchdog#DEFAULT_TIMEOUT}.
+     */
     @VisibleForTesting
-    static final long BOOT_TRIGGER_WINDOW_MILLIS = 300 * DateUtils.SECOND_IN_MILLIS;
+    static final long BOOT_TRIGGER_WINDOW_MILLIS = 600 * DateUtils.SECOND_IN_MILLIS;
     @VisibleForTesting
     static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS;
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6c1ffa7..baec3cc 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -802,8 +802,8 @@
                 }
             });
         // For now, simply clone property when it changes
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE,
-                mContext.getMainExecutor(), (namespace, name, value) -> {
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE,
+                mContext.getMainExecutor(), (properties) -> {
                     refreshIsolatedStorageSettings();
                 });
         refreshIsolatedStorageSettings();
@@ -1063,11 +1063,7 @@
     }
 
      private boolean supportsBlockCheckpoint() throws RemoteException {
-        // Only the system process is permitted to start checkpoints
-        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
-            throw new SecurityException("no permission to check block based checkpoint support");
-        }
-
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
         return mVold.supportsBlockCheckpoint();
     }
 
@@ -2726,11 +2722,7 @@
      */
     @Override
     public boolean needsCheckpoint() throws RemoteException {
-        // Only the system process is permitted to commit checkpoints
-        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
-            throw new SecurityException("no permission to commit checkpoint changes");
-        }
-
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
         return mVold.needsCheckpoint();
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 76136df..df92106 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -634,7 +634,7 @@
         }
 
         if (allowBackgroundActivityStarts) {
-            r.hasStartedWhitelistingBgActivityStarts = true;
+            r.setHasStartedWhitelistingBgActivityStarts(true);
             scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(r);
         }
 
@@ -761,11 +761,6 @@
         }
         service.callStart = false;
 
-        // the service will not necessarily be brought down, so only clear the whitelisting state
-        // for start-based bg activity starts now, and drop any existing future cleanup callback
-        service.setHasStartedWhitelistingBgActivityStarts(false);
-        mAm.mHandler.removeCallbacks(service.startedWhitelistingBgActivityStartsCleanUp);
-
         bringDownServiceIfNeededLocked(service, false, false);
     }
 
@@ -1768,12 +1763,7 @@
                     callerApp.uid, callerApp.processName, callingPackage);
 
             IBinder binder = connection.asBinder();
-            ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
-            if (clist == null) {
-                clist = new ArrayList<ConnectionRecord>();
-                s.putConnection(binder, clist);
-            }
-            clist.add(c);
+            s.addConnection(binder, c);
             b.connections.add(c);
             if (activity != null) {
                 activity.addConnection(c);
@@ -1792,9 +1782,9 @@
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app, c, true);
             }
-            clist = mServiceConnections.get(binder);
+            ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
             if (clist == null) {
-                clist = new ArrayList<ConnectionRecord>();
+                clist = new ArrayList<>();
                 mServiceConnections.put(binder, clist);
             }
             clist.add(c);
@@ -3828,8 +3818,8 @@
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
         int userId = UserHandle.getUserId(Binder.getCallingUid());
         ServiceRecord r = getServiceByNameLocked(name, userId);
-        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
         if (r != null) {
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
             for (int conni = connections.size() - 1; conni >= 0; conni--) {
                 ArrayList<ConnectionRecord> conn = connections.valueAt(conni);
                 for (int i=0; i<conn.size(); i++) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index d7decb4..0da39e7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -26,7 +26,8 @@
 import android.os.Build;
 import android.os.Handler;
 import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.OnPropertyChangedListener;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DeviceConfig.Properties;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
@@ -315,23 +316,25 @@
     private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
             Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
 
-    private final OnPropertyChangedListener mOnDeviceConfigChangedListener =
-            new OnPropertyChangedListener() {
+    private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
+            new OnPropertiesChangedListener() {
                 @Override
-                public void onPropertyChanged(String namespace, String name, String value) {
-                    if (name == null) {
-                        return;
-                    }
-                    switch (name) {
-                        case KEY_MAX_CACHED_PROCESSES:
-                            updateMaxCachedProcesses();
-                            break;
-                        case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
-                        case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
-                            updateBackgroundActivityStarts();
-                            break;
-                        default:
-                            break;
+                public void onPropertiesChanged(Properties properties) {
+                    for (String name : properties.getKeyset()) {
+                        if (name == null) {
+                            return;
+                        }
+                        switch (name) {
+                            case KEY_MAX_CACHED_PROCESSES:
+                                updateMaxCachedProcesses();
+                                break;
+                            case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
+                            case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
+                                updateBackgroundActivityStarts();
+                                break;
+                            default:
+                                break;
+                        }
                     }
                 }
             };
@@ -362,7 +365,7 @@
         if (mSystemServerAutomaticHeapDumpEnabled) {
             updateEnableAutomaticSystemServerHeapDumps();
         }
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 ActivityThread.currentApplication().getMainExecutor(),
                 mOnDeviceConfigChangedListener);
         updateMaxCachedProcesses();
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 13b55db..b0f8f86 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -30,7 +30,8 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.OnPropertyChangedListener;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DeviceConfig.Properties;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Slog;
@@ -126,29 +127,31 @@
     private final ArrayList<ProcessRecord> mPendingCompactionProcesses =
             new ArrayList<ProcessRecord>();
     private final ActivityManagerService mAm;
-    private final OnPropertyChangedListener mOnFlagsChangedListener =
-            new OnPropertyChangedListener() {
+    private final OnPropertiesChangedListener mOnFlagsChangedListener =
+            new OnPropertiesChangedListener() {
                 @Override
-                public void onPropertyChanged(String namespace, String name, String value) {
+                public void onPropertiesChanged(Properties properties) {
                     synchronized (mPhenotypeFlagLock) {
-                        if (KEY_USE_COMPACTION.equals(name)) {
-                            updateUseCompaction();
-                        } else if (KEY_COMPACT_ACTION_1.equals(name)
-                                || KEY_COMPACT_ACTION_2.equals(name)) {
-                            updateCompactionActions();
-                        } else if (KEY_COMPACT_THROTTLE_1.equals(name)
-                                || KEY_COMPACT_THROTTLE_2.equals(name)
-                                || KEY_COMPACT_THROTTLE_3.equals(name)
-                                || KEY_COMPACT_THROTTLE_4.equals(name)) {
-                            updateCompactionThrottles();
-                        } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
-                            updateStatsdSampleRate();
-                        } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) {
-                            updateFullRssThrottle();
-                        } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) {
-                            updateFullDeltaRssThrottle();
-                        } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
-                            updateProcStateThrottle();
+                        for (String name : properties.getKeyset()) {
+                            if (KEY_USE_COMPACTION.equals(name)) {
+                                updateUseCompaction();
+                            } else if (KEY_COMPACT_ACTION_1.equals(name)
+                                    || KEY_COMPACT_ACTION_2.equals(name)) {
+                                updateCompactionActions();
+                            } else if (KEY_COMPACT_THROTTLE_1.equals(name)
+                                    || KEY_COMPACT_THROTTLE_2.equals(name)
+                                    || KEY_COMPACT_THROTTLE_3.equals(name)
+                                    || KEY_COMPACT_THROTTLE_4.equals(name)) {
+                                updateCompactionThrottles();
+                            } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
+                                updateStatsdSampleRate();
+                            } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) {
+                                updateFullRssThrottle();
+                            } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) {
+                                updateFullDeltaRssThrottle();
+                            } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
+                                updateProcStateThrottle();
+                            }
                         }
                     }
                     if (mTestCallback != null) {
@@ -229,7 +232,7 @@
      * starts the background thread if necessary.
      */
     public void init() {
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
         synchronized (mPhenotypeFlagLock) {
             updateUseCompaction();
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e891e6e..563b2f3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1186,8 +1186,8 @@
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
     }
 
-    void addBoundClientUids(ArraySet<Integer> clientUids) {
-        mBoundClientUids.addAll(clientUids);
+    void addBoundClientUid(int clientUid) {
+        mBoundClientUids.add(clientUid);
         mWindowProcessController.setBoundClientUids(mBoundClientUids);
     }
 
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 27c62d0..0426ec1 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -38,7 +38,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -131,10 +130,10 @@
     int pendingConnectionImportance;   // To be filled in to ProcessRecord once it connects
 
     // any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
-    private boolean hasBindingWhitelistingBgActivityStarts;
+    private boolean mHasBindingWhitelistingBgActivityStarts;
     // is this service currently whitelisted to start activities from background by providing
     // allowBackgroundActivityStarts=true to startServiceLocked()?
-    boolean hasStartedWhitelistingBgActivityStarts;
+    private boolean mHasStartedWhitelistingBgActivityStarts;
     // used to clean up the state of hasStartedWhitelistingBgActivityStarts after a timeout
     Runnable startedWhitelistingBgActivityStartsCleanUp;
 
@@ -384,13 +383,13 @@
         if (whitelistManager) {
             pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
         }
-        if (hasBindingWhitelistingBgActivityStarts) {
+        if (mHasBindingWhitelistingBgActivityStarts) {
             pw.print(prefix); pw.print("hasBindingWhitelistingBgActivityStarts=");
-            pw.println(hasBindingWhitelistingBgActivityStarts);
+            pw.println(mHasBindingWhitelistingBgActivityStarts);
         }
-        if (hasStartedWhitelistingBgActivityStarts) {
+        if (mHasStartedWhitelistingBgActivityStarts) {
             pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts=");
-            pw.println(hasStartedWhitelistingBgActivityStarts);
+            pw.println(mHasStartedWhitelistingBgActivityStarts);
         }
         if (delayed) {
             pw.print(prefix); pw.print("delayed="); pw.println(delayed);
@@ -542,7 +541,8 @@
 
     public void setProcess(ProcessRecord _proc) {
         if (_proc != null) {
-            if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+            if (mHasStartedWhitelistingBgActivityStarts
+                    || mHasBindingWhitelistingBgActivityStarts) {
                 _proc.addAllowBackgroundActivityStartsToken(this);
             } else {
                 _proc.removeAllowBackgroundActivityStartsToken(this);
@@ -580,15 +580,17 @@
         return connections;
     }
 
-    void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) {
-        connections.put(binder, clist);
-        // if we have a process attached, add bound client uids of this connection to it
+    void addConnection(IBinder binder, ConnectionRecord c) {
+        ArrayList<ConnectionRecord> clist = connections.get(binder);
+        if (clist == null) {
+            clist = new ArrayList<>();
+            connections.put(binder, clist);
+        }
+        clist.add(c);
+
+        // if we have a process attached, add bound client uid of this connection to it
         if (app != null) {
-            ArraySet<Integer> boundClientUids = new ArraySet<>();
-            for (int i = 0; i < clist.size(); i++) {
-                boundClientUids.add(clist.get(i).clientUid);
-            }
-            app.addBoundClientUids(boundClientUids);
+            app.addBoundClientUid(c.clientUid);
         }
     }
 
@@ -614,22 +616,22 @@
                 break;
             }
         }
-        if (hasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) {
-            hasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding;
+        if (mHasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) {
+            mHasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding;
             updateParentProcessBgActivityStartsWhitelistingToken();
         }
     }
 
     void setHasBindingWhitelistingBgActivityStarts(boolean newValue) {
-        if (hasBindingWhitelistingBgActivityStarts != newValue) {
-            hasBindingWhitelistingBgActivityStarts = newValue;
+        if (mHasBindingWhitelistingBgActivityStarts != newValue) {
+            mHasBindingWhitelistingBgActivityStarts = newValue;
             updateParentProcessBgActivityStartsWhitelistingToken();
         }
     }
 
     void setHasStartedWhitelistingBgActivityStarts(boolean newValue) {
-        if (hasStartedWhitelistingBgActivityStarts != newValue) {
-            hasStartedWhitelistingBgActivityStarts = newValue;
+        if (mHasStartedWhitelistingBgActivityStarts != newValue) {
+            mHasStartedWhitelistingBgActivityStarts = newValue;
             updateParentProcessBgActivityStartsWhitelistingToken();
         }
     }
@@ -647,7 +649,7 @@
         if (app == null) {
             return;
         }
-        if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+        if (mHasStartedWhitelistingBgActivityStarts || mHasBindingWhitelistingBgActivityStarts) {
             // if the token is already there it's safe to "re-add it" - we're deadling with
             // a set of Binder objects
             app.addAllowBackgroundActivityStartsToken(this);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 507f398..d510912 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1825,14 +1825,28 @@
                             && streamTypeAlias == AudioSystem.STREAM_MUSIC
                             // vol change on a full volume device
                             && ((device & mFullVolumeDevices) != 0)) {
-                        int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
-                                KeyEvent.KEYCODE_VOLUME_UP;
-                        final long ident = Binder.clearCallingIdentity();
-                        try {
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
-                        } finally {
-                            Binder.restoreCallingIdentity(ident);
+                        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+                        switch (direction) {
+                            case AudioManager.ADJUST_RAISE:
+                                keyCode = KeyEvent.KEYCODE_VOLUME_UP;
+                                break;
+                            case AudioManager.ADJUST_LOWER:
+                                keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
+                                break;
+                            case AudioManager.ADJUST_TOGGLE_MUTE:
+                                keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
+                                break;
+                            default:
+                                break;
+                        }
+                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            final long ident = Binder.clearCallingIdentity();
+                            try {
+                                mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
+                                mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+                            } finally {
+                                Binder.restoreCallingIdentity(ident);
+                            }
                         }
                     }
 
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 0f73f37..d439653 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -37,6 +37,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
 import android.provider.Settings;
 import android.util.Base64;
 import android.util.Slog;
@@ -138,18 +139,19 @@
         }
     }
 
-    private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener {
+    private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
 
         DeviceConfigListener() {
             super();
-            DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
+            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
                     mContext.getMainExecutor(), this);
         }
         @Override
-        public void onPropertyChanged(String namespace, String name, String value) {
+        public void onPropertiesChanged(Properties properties) {
             synchronized (mDeviceConfigLock) {
-                if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) {
-                    parseBlacklists(value != null ? value : "");
+                if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) {
+                    parseBlacklists(
+                            properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, ""));
                     setBlacklist();
                 }
             }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 651ce7d..30d244f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1409,7 +1409,7 @@
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-        mImeDisplayValidator = mWindowManagerInternal::shouldShowSystemDecorOnDisplay;
+        mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
         mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
@@ -2139,7 +2139,9 @@
         if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
             return FALLBACK_DISPLAY_ID;
         }
-        // Show IME window on fallback display when the display is not allowed.
+
+        // Show IME window on fallback display when the display doesn't support system decorations
+        // or the display is virtual and isn't owned by system for security concern.
         return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 580150e..e0b8e71 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -79,6 +79,9 @@
 import com.android.internal.inputmethod.UnbindReason;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -90,6 +93,8 @@
 import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.util.Collections;
 import java.util.List;
@@ -645,6 +650,14 @@
             mSelfReportedDisplayId = selfReportedDisplayId;
             mClientId = InputMethodClientIdSource.getNext();
         }
+
+        @GuardedBy("PerUserData.mLock")
+        void dumpLocked(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+            ipw.println("mState=" + mState + ",mBindingSequence=" + mBindingSequence
+                    + ",mWriteChannel=" + mWriteChannel
+                    + ",mInputMethodSession=" + mInputMethodSession
+                    + ",mMSInputMethodSession=" + mMSInputMethodSession);
+        }
     }
 
     private static final class UserDataMap {
@@ -673,6 +686,22 @@
                 return mMap.removeReturnOld(userId);
             }
         }
+
+        @AnyThread
+        void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+            synchronized (mMap) {
+                for (int i = 0; i < mMap.size(); i++) {
+                    int userId = mMap.keyAt(i);
+                    PerUserData data = mMap.valueAt(i);
+                    ipw.println("userId=" + userId + ", data=");
+                    if (data != null) {
+                        ipw.increaseIndent();
+                        data.dump(fd, ipw, args);
+                        ipw.decreaseIndent();
+                    }
+                }
+            }
+        }
     }
 
     private static final class TokenInfo {
@@ -967,6 +996,71 @@
             }
         }
 
+        @AnyThread
+        void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+            synchronized (mLock) {
+                ipw.println("mState=" + mState
+                        + ",mCurrentInputMethod=" + mCurrentInputMethod
+                        + ",mCurrentInputMethodInfo=" + mCurrentInputMethodInfo);
+
+                if (mCurrentInputMethod != null) {
+                    // indentation will not be kept. So add visual separator here.
+                    ipw.println(">>Dump CurrentInputMethod>>");
+                    ipw.flush();
+                    try {
+                        TransferPipe.dumpAsync(mCurrentInputMethod.asBinder(), fd, args);
+                    } catch (IOException | RemoteException e) {
+                        ipw.println("Failed to dump input method service: " + e);
+                    }
+                    ipw.println("<<Dump CurrentInputMethod<<");
+                }
+
+                ipw.println("mDisplayIdToImeWindowTokenMap=");
+                for (TokenInfo info : mDisplayIdToImeWindowTokenMap) {
+                    ipw.println(" display=" + info.mDisplayId + ",token="
+                            + info.mToken);
+                }
+                ipw.println("mClientMap=");
+                ipw.increaseIndent();
+                for (int i = 0; i < mClientMap.size(); i++) {
+
+                    ipw.println("binder=" + mClientMap.keyAt(i));
+                    ipw.println(" InputMethodClientInfo=");
+                    InputMethodClientInfo info = mClientMap.valueAt(i);
+                    if (info != null) {
+                        ipw.increaseIndent();
+                        info.dumpLocked(fd, ipw, args);
+                        ipw.decreaseIndent();
+                    }
+                }
+                ipw.decreaseIndent();
+                ipw.println("mClientIdToClientMap=");
+                ipw.increaseIndent();
+                for (int i = 0; i < mClientIdToClientMap.size(); i++) {
+                    ipw.println("clientId=" + mClientIdToClientMap.keyAt(i));
+                    ipw.println(" InputMethodClientInfo=");
+                    InputMethodClientInfo info = mClientIdToClientMap.valueAt(i);
+                    if (info != null) {
+                        ipw.increaseIndent();
+                        info.dumpLocked(fd, ipw, args);
+                        ipw.decreaseIndent();
+                    }
+                    if (info.mClient != null) {
+                        // indentation will not be kept. So add visual separator here.
+                        ipw.println(">>DumpClientStart>>");
+                        ipw.flush(); // all writes should be flushed to guarantee order.
+                        try {
+                            TransferPipe.dumpAsync(info.mClient.asBinder(), fd, args);
+                        } catch (IOException | RemoteException e) {
+                            ipw.println(" Failed to dump client:" + e);
+                        }
+                        ipw.println("<<DumpClientEnd<<");
+                    }
+                }
+                ipw.decreaseIndent();
+            }
+        }
+
         private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
             private final PerUserData mPerUserData;
             private final IInputMethodClient mClient;
@@ -1106,6 +1200,16 @@
             }
             return Collections.singletonList(info);
         }
+
+        @AnyThread
+        void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+            synchronized (mArray) {
+                for (int i = 0; i < mArray.size(); i++) {
+                    ipw.println("userId=" + mArray.keyAt(i));
+                    ipw.println(" InputMethodInfo=" + mArray.valueAt(i));
+                }
+            }
+        }
     }
 
     /**
@@ -1601,5 +1705,19 @@
                 @Nullable FileDescriptor err, String[] args, @Nullable ShellCallback callback,
                 ResultReceiver resultReceiver) {
         }
+
+        @BinderThread
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+            final String prefixChild = "  ";
+            pw.println("Current Multi Client Input Method Manager state:");
+            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+            ipw.println("mUserDataMap=");
+            if (mUserDataMap != null) {
+                ipw.increaseIndent();
+                mUserDataMap.dump(fd, ipw, args);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3a397cd..b676618 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -464,32 +464,6 @@
         private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
         private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
         private static final String KEY_USE_HEARTBEATS = "use_heartbeats";
-        private static final String KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS =
-                "tc_skip_not_ready_jobs";
-        private static final String KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
-                "qc_allowed_time_per_period_ms";
-        private static final String KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
-                "qc_in_quota_buffer_ms";
-        private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
-                "qc_window_size_active_ms";
-        private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
-                "qc_window_size_working_ms";
-        private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
-                "qc_window_size_frequent_ms";
-        private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
-                "qc_window_size_rare_ms";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
-                "qc_max_execution_time_ms";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
-                "qc_max_job_count_active";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
-                "qc_max_job_count_working";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
-                "qc_max_job_count_frequent";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
-                "qc_max_job_count_rare";
-        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
-                "qc_max_count_per_allowed_time";
 
         private static final int DEFAULT_MIN_IDLE_COUNT = 1;
         private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -511,30 +485,6 @@
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
         private static final boolean DEFAULT_USE_HEARTBEATS = false;
-        private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
-                10 * 60 * 1000L; // 10 minutes
-        private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
-                30 * 1000L; // 30 seconds
-        private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
-                10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
-        private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
-                2 * 60 * 60 * 1000L; // 2 hours
-        private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
-                8 * 60 * 60 * 1000L; // 8 hours
-        private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
-                24 * 60 * 60 * 1000L; // 24 hours
-        private static final long DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
-                4 * 60 * 60 * 1000L; // 4 hours
-        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
-                200; // 1200/hr
-        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
-                1200; // 600/hr
-        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
-                1800; // 225/hr
-        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
-                2400; // 100/hr
-        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20;
 
         /**
          * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -681,97 +631,6 @@
          */
         public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS;
 
-        /**
-         * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
-         * ready now.
-         */
-        public boolean TIME_CONTROLLER_SKIP_NOT_READY_JOBS =
-                DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS;
-
-        /** How much time each app will have to run jobs within their standby bucket window. */
-        public long QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
-                DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
-
-        /**
-         * How much time the package should have before transitioning from out-of-quota to in-quota.
-         * This should not affect processing if the package is already in-quota.
-         */
-        public long QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
-                DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
-
-        /**
-         * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
-         * WINDOW_SIZE_MS.
-         */
-        public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
-                DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS;
-
-        /**
-         * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
-         * WINDOW_SIZE_MS.
-         */
-        public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
-                DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS;
-
-        /**
-         * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
-         * WINDOW_SIZE_MS.
-         */
-        public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
-                DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS;
-
-        /**
-         * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
-         * WINDOW_SIZE_MS.
-         */
-        public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
-                DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS;
-
-        /**
-         * The maximum amount of time an app can have its jobs running within a 24 hour window.
-         */
-        public long QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
-                DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS;
-
-        /**
-         * The maximum number of jobs an app can run within this particular standby bucket's
-         * window size.
-         */
-        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
-                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE;
-
-        /**
-         * The maximum number of jobs an app can run within this particular standby bucket's
-         * window size.
-         */
-        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
-                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING;
-
-        /**
-         * The maximum number of jobs an app can run within this particular standby bucket's
-         * window size.
-         */
-        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
-                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT;
-
-        /**
-         * The maximum number of jobs an app can run within this particular standby bucket's
-         * window size.
-         */
-        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
-                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE;
-
-        /**
-         * The maximum number of jobs that can run within the past
-         * {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS}.
-         */
-        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
-                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
-
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
         void updateConstantsLocked(String value) {
@@ -835,45 +694,6 @@
             CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
                     DEFAULT_CONN_PREFETCH_RELAX_FRAC);
             USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS);
-            TIME_CONTROLLER_SKIP_NOT_READY_JOBS = mParser.getBoolean(
-                    KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS,
-                    DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS);
-            QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
-                    DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
-            QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
-                    DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
-            QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
-                    DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
-            QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
-                    DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
-            QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
-                    DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
-            QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
-                    DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
-            QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = mParser.getDurationMillis(
-                    KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
-            QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = mParser.getInt(
-                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
-            QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = mParser.getInt(
-                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
-            QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = mParser.getInt(
-                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
-            QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = mParser.getInt(
-                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
-            QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt(
-                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
-                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
         }
 
         void dump(IndentingPrintWriter pw) {
@@ -916,37 +736,11 @@
             pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
             pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
             pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println();
-            pw.printPair(KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS,
-                    TIME_CONTROLLER_SKIP_NOT_READY_JOBS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
-                    QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
-                    QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
-                    QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE).println();
-            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME).println();
+
             pw.decreaseIndent();
         }
 
-        void dump(ProtoOutputStream proto, long fieldId) {
-            final long token = proto.start(fieldId);
+        void dump(ProtoOutputStream proto) {
             proto.write(ConstantsProto.MIN_IDLE_COUNT, MIN_IDLE_COUNT);
             proto.write(ConstantsProto.MIN_CHARGING_COUNT, MIN_CHARGING_COUNT);
             proto.write(ConstantsProto.MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT);
@@ -974,40 +768,6 @@
             proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
             proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
             proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS);
-
-            final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
-            proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS,
-                    TIME_CONTROLLER_SKIP_NOT_READY_JOBS);
-            proto.end(tcToken);
-
-            final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER);
-            proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS,
-                    QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
-            proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS,
-                    QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
-            proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
-            proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
-            proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
-            proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS,
-                    QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
-            proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS,
-                    QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
-            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
-            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
-            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
-            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
-            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME,
-                    QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
-            proto.end(qcToken);
-
-            proto.end(token);
         }
     }
 
@@ -1637,6 +1397,9 @@
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
             mConstantsObserver.start(getContext().getContentResolver());
+            for (StateController controller : mControllers) {
+                controller.onSystemServicesReady();
+            }
 
             mAppStateTracker = Preconditions.checkNotNull(
                     LocalServices.getService(AppStateTracker.class));
@@ -3448,6 +3211,11 @@
         };
         synchronized (mLock) {
             mConstants.dump(pw);
+            for (StateController controller : mControllers) {
+                pw.increaseIndent();
+                controller.dumpConstants(pw);
+                pw.decreaseIndent();
+            }
             pw.println();
 
             pw.println("  Heartbeat:");
@@ -3638,7 +3406,13 @@
         };
 
         synchronized (mLock) {
-            mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS);
+            final long settingsToken = proto.start(JobSchedulerServiceDumpProto.SETTINGS);
+            mConstants.dump(proto);
+            for (StateController controller : mControllers) {
+                controller.dumpConstants(proto);
+            }
+            proto.end(settingsToken);
+
             proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat);
             proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]);
             proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]);
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 11f0939..2a9d3f3 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -34,9 +34,12 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
 import android.os.Handler;
@@ -44,8 +47,10 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -57,6 +62,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
+import com.android.server.job.ConstantsProto;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.StateControllerProto;
 
@@ -354,6 +360,7 @@
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
     private final Handler mHandler;
+    private final QcConstants mQcConstants;
 
     private volatile boolean mInParole;
 
@@ -489,6 +496,7 @@
         mChargeTracker.startTracking();
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mQcConstants = new QcConstants(mHandler);
 
         final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
@@ -506,7 +514,12 @@
             // ignored; both services live in system_server
         }
 
-        onConstantsUpdatedLocked();
+        mShouldThrottle = !mConstants.USE_HEARTBEATS;
+    }
+
+    @Override
+    public void onSystemServicesReady() {
+        mQcConstants.start(mContext.getContentResolver());
     }
 
     @Override
@@ -581,89 +594,9 @@
 
     @Override
     public void onConstantsUpdatedLocked() {
-        boolean changed = false;
         if (mShouldThrottle == mConstants.USE_HEARTBEATS) {
             mShouldThrottle = !mConstants.USE_HEARTBEATS;
-            changed = true;
-        }
-        long newAllowedTimeMs = Math.min(MAX_PERIOD_MS,
-                Math.max(MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS));
-        if (mAllowedTimePerPeriodMs != newAllowedTimeMs) {
-            mAllowedTimePerPeriodMs = newAllowedTimeMs;
-            mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
-            changed = true;
-        }
-        long newQuotaBufferMs = Math.max(0,
-                Math.min(5 * MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS));
-        if (mQuotaBufferMs != newQuotaBufferMs) {
-            mQuotaBufferMs = newQuotaBufferMs;
-            mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
-            mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
-            changed = true;
-        }
-        long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs,
-                Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS));
-        if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) {
-            mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs;
-            changed = true;
-        }
-        long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs,
-                Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS));
-        if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) {
-            mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs;
-            changed = true;
-        }
-        long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs,
-                Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS));
-        if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) {
-            mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs;
-            changed = true;
-        }
-        long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs,
-                Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS));
-        if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) {
-            mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs;
-            changed = true;
-        }
-        long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS,
-                Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS));
-        if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) {
-            mMaxExecutionTimeMs = newMaxExecutionTimeMs;
-            mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
-            changed = true;
-        }
-        int newMaxCountPerAllowedPeriod = Math.max(10,
-                mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
-        if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) {
-            mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod;
-            changed = true;
-        }
-        int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
-                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE));
-        if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) {
-            mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount;
-            changed = true;
-        }
-        int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
-                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING));
-        if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) {
-            mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount;
-            changed = true;
-        }
-        int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
-                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT));
-        if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) {
-            mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount;
-            changed = true;
-        }
-        int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
-                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE));
-        if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) {
-            mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount;
-            changed = true;
-        }
 
-        if (changed) {
             // Update job bookkeeping out of band.
             BackgroundThread.getHandler().post(() -> {
                 synchronized (mLock) {
@@ -1891,6 +1824,311 @@
         }
     }
 
+    @VisibleForTesting
+    class QcConstants extends ContentObserver {
+        private ContentResolver mResolver;
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+        private static final String KEY_ALLOWED_TIME_PER_PERIOD_MS = "allowed_time_per_period_ms";
+        private static final String KEY_IN_QUOTA_BUFFER_MS = "in_quota_buffer_ms";
+        private static final String KEY_WINDOW_SIZE_ACTIVE_MS = "window_size_active_ms";
+        private static final String KEY_WINDOW_SIZE_WORKING_MS = "window_size_working_ms";
+        private static final String KEY_WINDOW_SIZE_FREQUENT_MS = "window_size_frequent_ms";
+        private static final String KEY_WINDOW_SIZE_RARE_MS = "window_size_rare_ms";
+        private static final String KEY_MAX_EXECUTION_TIME_MS = "max_execution_time_ms";
+        private static final String KEY_MAX_JOB_COUNT_ACTIVE = "max_job_count_active";
+        private static final String KEY_MAX_JOB_COUNT_WORKING = "max_job_count_working";
+        private static final String KEY_MAX_JOB_COUNT_FREQUENT = "max_job_count_frequent";
+        private static final String KEY_MAX_JOB_COUNT_RARE = "max_job_count_rare";
+        private static final String KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME =
+                "max_count_per_allowed_time";
+
+        private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
+                10 * 60 * 1000L; // 10 minutes
+        private static final long DEFAULT_IN_QUOTA_BUFFER_MS =
+                30 * 1000L; // 30 seconds
+        private static final long DEFAULT_WINDOW_SIZE_ACTIVE_MS =
+                10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
+        private static final long DEFAULT_WINDOW_SIZE_WORKING_MS =
+                2 * 60 * 60 * 1000L; // 2 hours
+        private static final long DEFAULT_WINDOW_SIZE_FREQUENT_MS =
+                8 * 60 * 60 * 1000L; // 8 hours
+        private static final long DEFAULT_WINDOW_SIZE_RARE_MS =
+                24 * 60 * 60 * 1000L; // 24 hours
+        private static final long DEFAULT_MAX_EXECUTION_TIME_MS =
+                4 * 60 * 60 * 1000L; // 4 hours
+        private static final int DEFAULT_MAX_JOB_COUNT_ACTIVE =
+                200; // 1200/hr
+        private static final int DEFAULT_MAX_JOB_COUNT_WORKING =
+                1200; // 600/hr
+        private static final int DEFAULT_MAX_JOB_COUNT_FREQUENT =
+                1800; // 225/hr
+        private static final int DEFAULT_MAX_JOB_COUNT_RARE =
+                2400; // 100/hr
+        private static final int DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20;
+
+        /** How much time each app will have to run jobs within their standby bucket window. */
+        public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
+
+        /**
+         * How much time the package should have before transitioning from out-of-quota to in-quota.
+         * This should not affect processing if the package is already in-quota.
+         */
+        public long IN_QUOTA_BUFFER_MS = DEFAULT_IN_QUOTA_BUFFER_MS;
+
+        /**
+         * The quota window size of the particular standby bucket. Apps in this standby bucket are
+         * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * WINDOW_SIZE_MS.
+         */
+        public long WINDOW_SIZE_ACTIVE_MS = DEFAULT_WINDOW_SIZE_ACTIVE_MS;
+
+        /**
+         * The quota window size of the particular standby bucket. Apps in this standby bucket are
+         * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * WINDOW_SIZE_MS.
+         */
+        public long WINDOW_SIZE_WORKING_MS = DEFAULT_WINDOW_SIZE_WORKING_MS;
+
+        /**
+         * The quota window size of the particular standby bucket. Apps in this standby bucket are
+         * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * WINDOW_SIZE_MS.
+         */
+        public long WINDOW_SIZE_FREQUENT_MS = DEFAULT_WINDOW_SIZE_FREQUENT_MS;
+
+        /**
+         * The quota window size of the particular standby bucket. Apps in this standby bucket are
+         * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * WINDOW_SIZE_MS.
+         */
+        public long WINDOW_SIZE_RARE_MS = DEFAULT_WINDOW_SIZE_RARE_MS;
+
+        /**
+         * The maximum amount of time an app can have its jobs running within a 24 hour window.
+         */
+        public long MAX_EXECUTION_TIME_MS = DEFAULT_MAX_EXECUTION_TIME_MS;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int MAX_JOB_COUNT_ACTIVE = DEFAULT_MAX_JOB_COUNT_ACTIVE;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int MAX_JOB_COUNT_WORKING = DEFAULT_MAX_JOB_COUNT_WORKING;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int MAX_JOB_COUNT_FREQUENT = DEFAULT_MAX_JOB_COUNT_FREQUENT;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int MAX_JOB_COUNT_RARE = DEFAULT_MAX_JOB_COUNT_RARE;
+
+        /**
+         * The maximum number of jobs that can run within the past
+         * {@link #ALLOWED_TIME_PER_PERIOD_MS}.
+         */
+        public int MAX_JOB_COUNT_PER_ALLOWED_TIME = DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+
+        QcConstants(Handler handler) {
+            super(handler);
+        }
+
+        private void start(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS), false, this);
+            updateConstants();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            final String constants = Settings.Global.getString(
+                    mResolver, Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
+
+            try {
+                mParser.setString(constants);
+            } catch (Exception e) {
+                // Failed to parse the settings string, log this and move on with defaults.
+                Slog.e(TAG, "Bad jobscheduler quota controller settings", e);
+            }
+
+            ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis(
+                    KEY_ALLOWED_TIME_PER_PERIOD_MS, DEFAULT_ALLOWED_TIME_PER_PERIOD_MS);
+            IN_QUOTA_BUFFER_MS = mParser.getDurationMillis(
+                    KEY_IN_QUOTA_BUFFER_MS, DEFAULT_IN_QUOTA_BUFFER_MS);
+            WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis(
+                    KEY_WINDOW_SIZE_ACTIVE_MS, DEFAULT_WINDOW_SIZE_ACTIVE_MS);
+            WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis(
+                    KEY_WINDOW_SIZE_WORKING_MS, DEFAULT_WINDOW_SIZE_WORKING_MS);
+            WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis(
+                    KEY_WINDOW_SIZE_FREQUENT_MS, DEFAULT_WINDOW_SIZE_FREQUENT_MS);
+            WINDOW_SIZE_RARE_MS = mParser.getDurationMillis(
+                    KEY_WINDOW_SIZE_RARE_MS, DEFAULT_WINDOW_SIZE_RARE_MS);
+            MAX_EXECUTION_TIME_MS = mParser.getDurationMillis(
+                    KEY_MAX_EXECUTION_TIME_MS, DEFAULT_MAX_EXECUTION_TIME_MS);
+            MAX_JOB_COUNT_ACTIVE = mParser.getInt(
+                    KEY_MAX_JOB_COUNT_ACTIVE, DEFAULT_MAX_JOB_COUNT_ACTIVE);
+            MAX_JOB_COUNT_WORKING = mParser.getInt(
+                    KEY_MAX_JOB_COUNT_WORKING, DEFAULT_MAX_JOB_COUNT_WORKING);
+            MAX_JOB_COUNT_FREQUENT = mParser.getInt(
+                    KEY_MAX_JOB_COUNT_FREQUENT, DEFAULT_MAX_JOB_COUNT_FREQUENT);
+            MAX_JOB_COUNT_RARE = mParser.getInt(
+                    KEY_MAX_JOB_COUNT_RARE, DEFAULT_MAX_JOB_COUNT_RARE);
+            MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt(
+                    KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME);
+
+            updateConstants();
+        }
+
+        @VisibleForTesting
+        void updateConstants() {
+            synchronized (mLock) {
+                boolean changed = false;
+
+                long newAllowedTimeMs = Math.min(MAX_PERIOD_MS,
+                        Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_MS));
+                if (mAllowedTimePerPeriodMs != newAllowedTimeMs) {
+                    mAllowedTimePerPeriodMs = newAllowedTimeMs;
+                    mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
+                    changed = true;
+                }
+                long newQuotaBufferMs = Math.max(0,
+                        Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS));
+                if (mQuotaBufferMs != newQuotaBufferMs) {
+                    mQuotaBufferMs = newQuotaBufferMs;
+                    mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
+                    mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
+                    changed = true;
+                }
+                long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+                        Math.min(MAX_PERIOD_MS, WINDOW_SIZE_ACTIVE_MS));
+                if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) {
+                    mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs;
+                    changed = true;
+                }
+                long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+                        Math.min(MAX_PERIOD_MS, WINDOW_SIZE_WORKING_MS));
+                if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) {
+                    mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs;
+                    changed = true;
+                }
+                long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+                        Math.min(MAX_PERIOD_MS, WINDOW_SIZE_FREQUENT_MS));
+                if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) {
+                    mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs;
+                    changed = true;
+                }
+                long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+                        Math.min(MAX_PERIOD_MS, WINDOW_SIZE_RARE_MS));
+                if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) {
+                    mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs;
+                    changed = true;
+                }
+                long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS,
+                        Math.min(MAX_PERIOD_MS, MAX_EXECUTION_TIME_MS));
+                if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) {
+                    mMaxExecutionTimeMs = newMaxExecutionTimeMs;
+                    mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
+                    changed = true;
+                }
+                int newMaxCountPerAllowedPeriod = Math.max(10,
+                        MAX_JOB_COUNT_PER_ALLOWED_TIME);
+                if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) {
+                    mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod;
+                    changed = true;
+                }
+                int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                        Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE));
+                if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) {
+                    mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount;
+                    changed = true;
+                }
+                int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                        Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_WORKING));
+                if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) {
+                    mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount;
+                    changed = true;
+                }
+                int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                        Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_FREQUENT));
+                if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) {
+                    mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount;
+                    changed = true;
+                }
+                int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                        Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RARE));
+                if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) {
+                    mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount;
+                    changed = true;
+                }
+
+                if (changed && mShouldThrottle) {
+                    // Update job bookkeeping out of band.
+                    BackgroundThread.getHandler().post(() -> {
+                        synchronized (mLock) {
+                            maybeUpdateAllConstraintsLocked();
+                        }
+                    });
+                }
+            }
+        }
+
+        private void dump(IndentingPrintWriter pw) {
+            pw.println();
+            pw.println("QuotaController:");
+            pw.increaseIndent();
+            pw.printPair(KEY_ALLOWED_TIME_PER_PERIOD_MS, ALLOWED_TIME_PER_PERIOD_MS).println();
+            pw.printPair(KEY_IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS).println();
+            pw.printPair(KEY_WINDOW_SIZE_ACTIVE_MS, WINDOW_SIZE_ACTIVE_MS).println();
+            pw.printPair(KEY_WINDOW_SIZE_WORKING_MS, WINDOW_SIZE_WORKING_MS).println();
+            pw.printPair(KEY_WINDOW_SIZE_FREQUENT_MS, WINDOW_SIZE_FREQUENT_MS).println();
+            pw.printPair(KEY_WINDOW_SIZE_RARE_MS, WINDOW_SIZE_RARE_MS).println();
+            pw.printPair(KEY_MAX_EXECUTION_TIME_MS, MAX_EXECUTION_TIME_MS).println();
+            pw.printPair(KEY_MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE).println();
+            pw.printPair(KEY_MAX_JOB_COUNT_WORKING, MAX_JOB_COUNT_WORKING).println();
+            pw.printPair(KEY_MAX_JOB_COUNT_FREQUENT, MAX_JOB_COUNT_FREQUENT).println();
+            pw.printPair(KEY_MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE).println();
+            pw.printPair(KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, MAX_JOB_COUNT_PER_ALLOWED_TIME)
+                    .println();
+            pw.decreaseIndent();
+        }
+
+        private void dump(ProtoOutputStream proto) {
+            final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER);
+            proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS,
+                    ALLOWED_TIME_PER_PERIOD_MS);
+            proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS);
+            proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS,
+                    WINDOW_SIZE_ACTIVE_MS);
+            proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS,
+                    WINDOW_SIZE_WORKING_MS);
+            proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS,
+                    WINDOW_SIZE_FREQUENT_MS);
+            proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS, WINDOW_SIZE_RARE_MS);
+            proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS,
+                    MAX_EXECUTION_TIME_MS);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING,
+                    MAX_JOB_COUNT_WORKING);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT,
+                    MAX_JOB_COUNT_FREQUENT);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME,
+                    MAX_JOB_COUNT_PER_ALLOWED_TIME);
+            proto.end(qcToken);
+        }
+    }
+
     //////////////////////// TESTING HELPERS /////////////////////////////
 
     @VisibleForTesting
@@ -1943,6 +2181,12 @@
         return mTimingSessions.get(userId, packageName);
     }
 
+    @VisibleForTesting
+    @NonNull
+    QcConstants getQcConstants() {
+        return mQcConstants;
+    }
+
     //////////////////////////// DATA DUMP //////////////////////////////
 
     @Override
@@ -2188,4 +2432,14 @@
         proto.end(mToken);
         proto.end(token);
     }
+
+    @Override
+    public void dumpConstants(IndentingPrintWriter pw) {
+        mQcConstants.dump(pw);
+    }
+
+    @Override
+    public void dumpConstants(ProtoOutputStream proto) {
+        mQcConstants.dump(proto);
+    }
 }
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 74628fb..51be38b 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -52,6 +52,13 @@
     }
 
     /**
+     * Called when the system boot phase has reached
+     * {@link com.android.server.SystemService#PHASE_SYSTEM_SERVICES_READY}.
+     */
+    public void onSystemServicesReady() {
+    }
+
+    /**
      * Implement the logic here to decide whether a job should be tracked by this controller.
      * This logic is put here so the JobManager can be completely agnostic of Controller logic.
      * Also called when updating a task, so implementing controllers have to be aware of
@@ -127,4 +134,12 @@
             Predicate<JobStatus> predicate);
     public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
             Predicate<JobStatus> predicate);
+
+    /** Dump any internal constants the Controller may have. */
+    public void dumpConstants(IndentingPrintWriter pw) {
+    }
+
+    /** Dump any internal constants the Controller may have. */
+    public void dumpConstants(ProtoOutputStream proto) {
+    }
 }
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 70deb38..ababad9 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -18,13 +18,20 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.AlarmManager.OnAlarmListener;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -32,6 +39,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.job.ConstantsProto;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.StateControllerProto;
 
@@ -55,6 +63,9 @@
     /** Delay alarm tag for logging purposes */
     private final String DELAY_TAG = "*job.delay*";
 
+    private final Handler mHandler;
+    private final TcConstants mTcConstants;
+
     private long mNextJobExpiredElapsedMillis;
     private long mNextDelayExpiredElapsedMillis;
 
@@ -70,6 +81,14 @@
         mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
         mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
         mChainedAttributionEnabled = mService.isChainedAttributionEnabled();
+
+        mHandler = new Handler(mContext.getMainLooper());
+        mTcConstants = new TcConstants(mHandler);
+    }
+
+    @Override
+    public void onSystemServicesReady() {
+        mTcConstants.start(mContext.getContentResolver());
     }
 
     /**
@@ -118,7 +137,7 @@
                     job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE;
             final long delayExpiredElapsed =
                     job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE;
-            if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) {
+            if (mTcConstants.SKIP_NOT_READY_JOBS) {
                 if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
                     maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws);
                 }
@@ -148,14 +167,8 @@
     }
 
     @Override
-    public void onConstantsUpdatedLocked() {
-        checkExpiredDeadlinesAndResetAlarm();
-        checkExpiredDelaysAndResetAlarm();
-    }
-
-    @Override
     public void evaluateStateLocked(JobStatus job) {
-        if (!mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) {
+        if (!mTcConstants.SKIP_NOT_READY_JOBS) {
             return;
         }
 
@@ -248,7 +261,7 @@
                     }
                     it.remove();
                 } else {  // Sorted by expiry time, so take the next one and stop.
-                    if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
+                    if (mTcConstants.SKIP_NOT_READY_JOBS
                             && !wouldBeReadyWithConstraintLocked(
                             job, JobStatus.CONSTRAINT_DEADLINE)) {
                         if (DEBUG) {
@@ -308,7 +321,7 @@
                         ready = true;
                     }
                 } else {
-                    if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
+                    if (mTcConstants.SKIP_NOT_READY_JOBS
                             && !wouldBeReadyWithConstraintLocked(
                             job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
                         if (DEBUG) {
@@ -439,6 +452,87 @@
         }
     };
 
+    @VisibleForTesting
+    void recheckAlarmsLocked() {
+        checkExpiredDeadlinesAndResetAlarm();
+        checkExpiredDelaysAndResetAlarm();
+    }
+
+    @VisibleForTesting
+    class TcConstants extends ContentObserver {
+        private ContentResolver mResolver;
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+        private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs";
+
+        private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true;
+
+        /**
+         * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
+         * ready now.
+         */
+        public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS;
+
+        /**
+         * Creates a content observer.
+         *
+         * @param handler The handler to run {@link #onChange} on, or null if none.
+         */
+        TcConstants(Handler handler) {
+            super(handler);
+        }
+
+        private void start(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this);
+            onChange(true, null);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            final String constants = Settings.Global.getString(
+                    mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS);
+
+            try {
+                mParser.setString(constants);
+            } catch (Exception e) {
+                // Failed to parse the settings string, log this and move on with defaults.
+                Slog.e(TAG, "Bad jobscheduler time controller settings", e);
+            }
+
+            final boolean oldVal = SKIP_NOT_READY_JOBS;
+            SKIP_NOT_READY_JOBS = mParser.getBoolean(
+                    KEY_SKIP_NOT_READY_JOBS, DEFAULT_SKIP_NOT_READY_JOBS);
+
+            if (oldVal != SKIP_NOT_READY_JOBS) {
+                synchronized (mLock) {
+                    recheckAlarmsLocked();
+                }
+            }
+        }
+
+        private void dump(IndentingPrintWriter pw) {
+            pw.println();
+            pw.println("TimeController:");
+            pw.increaseIndent();
+            pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println();
+            pw.decreaseIndent();
+        }
+
+        private void dump(ProtoOutputStream proto) {
+            final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
+            proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS);
+            proto.end(tcToken);
+        }
+    }
+
+    @VisibleForTesting
+    @NonNull
+    TcConstants getTcConstants() {
+        return mTcConstants;
+    }
+
     @Override
     public void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate) {
@@ -513,4 +607,14 @@
         proto.end(mToken);
         proto.end(token);
     }
+
+    @Override
+    public void dumpConstants(IndentingPrintWriter pw) {
+        mTcConstants.dump(pw);
+    }
+
+    @Override
+    public void dumpConstants(ProtoOutputStream proto) {
+        mTcConstants.dump(proto);
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index c739650..1dffcf9 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -333,6 +333,7 @@
         String[] selectionArguments = new String[] {String.valueOf(userId)};
 
         ensureUserMetadataEntryExists(userId);
+        invalidateKeysForUser(userId);
         return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
     }
 
@@ -394,16 +395,13 @@
     /**
      * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.
      */
-    public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) {
+    public void invalidateKeysForUser(int userId) {
         SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
         ContentValues values = new ContentValues();
         values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
                 RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
-        String selection =
-                KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
-                + KeysEntry.COLUMN_NAME_GENERATION_ID + " < ?";
-        db.update(KeysEntry.TABLE_NAME, values, selection,
-            new String[] {String.valueOf(userId), String.valueOf(newGenerationId)});
+        String selection = KeysEntry.COLUMN_NAME_USER_ID + " = ?";
+        db.update(KeysEntry.TABLE_NAME, values, selection, new String[] {String.valueOf(userId)});
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 21a862a..55191db 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1811,14 +1811,15 @@
     }
 
     private void registerDeviceConfigChange() {
-        DeviceConfig.addOnPropertyChangedListener(
+        DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 getContext().getMainExecutor(),
-                (namespace, name, value) -> {
-                    if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
+                (properties) -> {
+                    if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
                         return;
                     }
-                    if (SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE.equals(name)) {
+                    if (properties.getKeyset()
+                            .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
                         mAssistants.resetDefaultAssistantsIfNecessary();
                     }
                 });
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 20d47ed..c0f09d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18762,6 +18762,7 @@
         boolean installedStateChanged = false;
         if (deletedPs != null) {
             if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+                final SparseBooleanArray changedUsers = new SparseBooleanArray();
                 synchronized (mPackages) {
                     clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
                     clearDefaultBrowserIfNeeded(packageName);
@@ -18793,10 +18794,9 @@
                             }
                         }
                     }
+                    clearPackagePreferredActivitiesLPw(
+                            deletedPs.name, changedUsers, UserHandle.USER_ALL);
                 }
-                final SparseBooleanArray changedUsers = new SparseBooleanArray();
-                clearPackagePreferredActivitiesLPw(
-                        deletedPs.name, changedUsers, UserHandle.USER_ALL);
                 if (changedUsers.size() > 0) {
                     updateDefaultHomeNotLocked(changedUsers);
                     postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index d8f07fe..748a661 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -32,7 +33,6 @@
 import android.os.HandlerThread;
 import android.os.PowerManager;
 import android.text.TextUtils;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.StatsLog;
 
@@ -77,74 +77,50 @@
     @Override
     public int onHealthCheckFailed(VersionedPackage failedPackage) {
         VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
-        if (moduleMetadataPackage == null) {
-            // Ignore failure, no mainline update available
-            return PackageHealthObserverImpact.USER_IMPACT_NONE;
-        }
 
-        if (getAvailableRollback(mContext.getSystemService(RollbackManager.class),
-                        failedPackage, moduleMetadataPackage) == null) {
+        if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage)
+                == null) {
             // Don't handle the notification, no rollbacks available for the package
             return PackageHealthObserverImpact.USER_IMPACT_NONE;
+        } else {
+            // Rollback is available, we may get a callback into #execute
+            return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
         }
-        // Rollback is available, we may get a callback into #execute
-        return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
     }
 
     @Override
     public boolean execute(VersionedPackage failedPackage) {
-        VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
-        if (moduleMetadataPackage == null) {
-            // Ignore failure, no mainline update available
-            return false;
-        }
-
         RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
-        Pair<RollbackInfo, Boolean> rollbackPair = getAvailableRollback(rollbackManager,
-                failedPackage, moduleMetadataPackage);
-        if (rollbackPair == null) {
+        VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
+        RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage);
+
+        if (rollback == null) {
             Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
                     + failedPackage.getPackageName() + "] with versionCode: ["
                     + failedPackage.getVersionCode() + "]");
             return false;
         }
 
-        RollbackInfo rollback = rollbackPair.first;
-        // We only log mainline package rollbacks, so check if rollback contains the
-        // module metadata provider, if it does, the rollback is a mainline rollback
-        boolean hasModuleMetadataPackage = rollbackPair.second;
-
-        if (hasModuleMetadataPackage) {
-            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
-                    moduleMetadataPackage.getPackageName(),
-                    moduleMetadataPackage.getVersionCode());
-        }
+        logEvent(moduleMetadataPackage,
+                StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE);
         LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
-            if (hasModuleMetadataPackage) {
-                int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
-                        RollbackManager.STATUS_FAILURE);
-                if (status == RollbackManager.STATUS_SUCCESS) {
-                    if (rollback.isStaged()) {
-                        int rollbackId = rollback.getRollbackId();
-                        BroadcastReceiver listener =
-                                listenForStagedSessionReady(rollbackManager, rollbackId,
-                                        moduleMetadataPackage);
-                        handleStagedSessionChange(rollbackManager, rollbackId, listener,
-                                moduleMetadataPackage);
-                    } else {
-                        StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                                StatsLog
-                                .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
-                                moduleMetadataPackage.getPackageName(),
-                                moduleMetadataPackage.getVersionCode());
-                    }
+            int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+                    RollbackManager.STATUS_FAILURE);
+            if (status == RollbackManager.STATUS_SUCCESS) {
+                if (rollback.isStaged()) {
+                    int rollbackId = rollback.getRollbackId();
+                    BroadcastReceiver listener =
+                            listenForStagedSessionReady(rollbackManager, rollbackId,
+                                    moduleMetadataPackage);
+                    handleStagedSessionChange(rollbackManager, rollbackId, listener,
+                            moduleMetadataPackage);
                 } else {
-                    StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
-                            moduleMetadataPackage.getPackageName(),
-                            moduleMetadataPackage.getVersionCode());
+                    logEvent(moduleMetadataPackage,
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
                 }
+            } else {
+                logEvent(moduleMetadataPackage,
+                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
             }
         });
 
@@ -193,26 +169,17 @@
         }
 
         String moduleMetadataPackageName = getModuleMetadataPackageName();
-        if (moduleMetadataPackageName == null) {
-            // Only log mainline staged rollbacks
-            return;
-        }
 
         // Use the version of the metadata package that was installed before
         // we rolled back for logging purposes.
         VersionedPackage moduleMetadataPackage = null;
         for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
-            if (moduleMetadataPackageName.equals(packageRollback.getPackageName())) {
+            if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) {
                 moduleMetadataPackage = packageRollback.getVersionRolledBackFrom();
                 break;
             }
         }
 
-        if (moduleMetadataPackage == null) {
-            // Only log mainline staged rollbacks
-            return;
-        }
-
         int sessionId = rollback.getCommittedSessionId();
         PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
         if (sessionInfo == null) {
@@ -220,42 +187,33 @@
             return;
         }
         if (sessionInfo.isStagedSessionApplied()) {
-            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
-                    moduleMetadataPackage.getPackageName(),
-                    moduleMetadataPackage.getVersionCode());
+            logEvent(moduleMetadataPackage,
+                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
         } else if (sessionInfo.isStagedSessionReady()) {
             // TODO: What do for staged session ready but not applied
         } else {
-            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
-                    moduleMetadataPackage.getPackageName(),
-                    moduleMetadataPackage.getVersionCode());
+            logEvent(moduleMetadataPackage,
+                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
         }
     }
 
-    private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager,
-            VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) {
+    private RollbackInfo getAvailableRollback(RollbackManager rollbackManager,
+            VersionedPackage failedPackage) {
         for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
-            // We only rollback mainline packages, so check if rollback contains the
-            // module metadata provider, if it does, the rollback is a mainline rollback
-            boolean hasModuleMetadataPackage = false;
-            boolean hasFailedPackage = false;
             for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
-                hasModuleMetadataPackage |= packageRollback.getPackageName().equals(
-                        moduleMetadataPackage.getPackageName());
-                hasFailedPackage |= packageRollback.getPackageName().equals(
+                boolean hasFailedPackage = packageRollback.getPackageName().equals(
                         failedPackage.getPackageName())
                         && packageRollback.getVersionRolledBackFrom().getVersionCode()
                         == failedPackage.getVersionCode();
-            }
-            if (hasFailedPackage) {
-                return new Pair<RollbackInfo, Boolean>(rollback, hasModuleMetadataPackage);
+                if (hasFailedPackage) {
+                    return rollback;
+                }
             }
         }
         return null;
     }
 
+    @Nullable
     private String getModuleMetadataPackageName() {
         String packageName = mContext.getResources().getString(
                 R.string.config_defaultModuleMetadataProvider);
@@ -265,6 +223,7 @@
         return packageName;
     }
 
+    @Nullable
     private VersionedPackage getModuleMetadataPackage() {
         String packageName = getModuleMetadataPackageName();
         if (packageName == null) {
@@ -311,18 +270,13 @@
                 if (sessionInfo.isStagedSessionReady()) {
                     mContext.unregisterReceiver(listener);
                     saveLastStagedRollbackId(rollbackId);
-                    StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+                    logEvent(moduleMetadataPackage,
                             StatsLog
-                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
-                            moduleMetadataPackage.getPackageName(),
-                            moduleMetadataPackage.getVersionCode());
+                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED);
                     mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
                 } else if (sessionInfo.isStagedSessionFailed()) {
-                    StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                            StatsLog
-                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
-                            moduleMetadataPackage.getPackageName(),
-                            moduleMetadataPackage.getVersionCode());
+                    logEvent(moduleMetadataPackage,
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
                     mContext.unregisterReceiver(listener);
                 }
             }
@@ -358,4 +312,12 @@
         mLastStagedRollbackIdFile.delete();
         return rollbackId;
     }
+
+    private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) {
+        Slog.i(TAG, "Watchdog event occurred of type: " + type);
+        if (moduleMetadataPackage != null) {
+            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, type,
+                    moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode());
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2321898..a3cef7f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2432,14 +2432,19 @@
         }
     }
 
-    private boolean shouldAnimate(int transit) {
+
+    @VisibleForTesting
+    boolean shouldAnimate(int transit) {
         final boolean isSplitScreenPrimary =
                 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
         final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
 
-        // Don't animate when the task runs recents animation.
+        // Don't animate while the task runs recents animation but only if we are in the mode
+        // where we cancel with deferred screenshot, which means that the controller has
+        // transformed the task.
         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
-        if (controller != null && controller.isAnimatingTask(getTask())) {
+        if (controller != null && controller.isAnimatingTask(getTask())
+                && controller.shouldCancelWithDeferredScreenshot()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 78c5dbd..75a8dd5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -481,7 +481,15 @@
     public abstract int getTopFocusedDisplayId();
 
     /**
-     * Checks whether this display should support showing system decorations.
+     * Checks if this display is configured and allowed to show system decorations.
      */
     public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
+
+    /**
+     * Indicates that the display should show IME.
+     *
+     * @param displayId The id of the display.
+     * @return {@code true} if the display should show IME when an input field become focused on it.
+     */
+    public abstract boolean shouldShowIme(int displayId);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dae29b2..4eddb30 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -163,6 +164,7 @@
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -6871,10 +6873,21 @@
                         + "not exist: " + displayId);
                 return false;
             }
+            final Display display = displayContent.getDisplay();
+            if (isUntrustedVirtualDisplay(display)) {
+                return false;
+            }
             return displayContent.supportsSystemDecorations();
         }
     }
 
+    /**
+     * @return {@code true} if the display is non-system created virtual display.
+     */
+    private static boolean isUntrustedVirtualDisplay(Display display) {
+        return display.getType() == TYPE_VIRTUAL && display.getOwnerUid() != Process.SYSTEM_UID;
+    }
+
     @Override
     public void setShouldShowSystemDecors(int displayId, boolean shouldShow) {
         if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowSystemDecors()")) {
@@ -6908,7 +6921,12 @@
                         + displayId);
                 return false;
             }
-            return mDisplayWindowSettings.shouldShowImeLocked(displayContent);
+            final Display display = displayContent.getDisplay();
+            if (isUntrustedVirtualDisplay(display)) {
+                return false;
+            }
+            return mDisplayWindowSettings.shouldShowImeLocked(displayContent)
+                    || mForceDesktopModeOnExternalDisplays;
         }
     }
 
@@ -7352,6 +7370,14 @@
                 return WindowManagerService.this.shouldShowSystemDecors(displayId);
             }
         }
+
+        @Override
+        public boolean shouldShowIme(int displayId) {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+                return mDisplayWindowSettings.shouldShowImeLocked(displayContent);
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 7c30f25..2e7283c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -105,8 +105,9 @@
     private static final int SOURCE_USER_ID = 0;
 
     private BroadcastReceiver mChargingReceiver;
-    private Constants mConstants;
+    private Constants mJsConstants;
     private QuotaController mQuotaController;
+    private QuotaController.QcConstants mQcConstants;
     private int mSourceUid;
     private IUidObserver mUidObserver;
 
@@ -132,13 +133,13 @@
                 .mockStatic(LocalServices.class)
                 .startMocking();
         // Make sure constants turn on QuotaController.
-        mConstants = new Constants();
-        mConstants.USE_HEARTBEATS = false;
+        mJsConstants = new Constants();
+        mJsConstants.USE_HEARTBEATS = false;
 
         // Called in StateController constructor.
         when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
         when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
-        when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
+        when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants);
         // Called in QuotaController constructor.
         IActivityManager activityManager = ActivityManager.getService();
         spyOn(activityManager);
@@ -196,6 +197,7 @@
         } catch (RemoteException e) {
             fail(e.getMessage());
         }
+        mQcConstants = mQuotaController.getQcConstants();
     }
 
     @After
@@ -531,7 +533,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 15;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
 
@@ -544,7 +546,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 15;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
 
@@ -557,7 +559,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 15;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
 
@@ -574,7 +576,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 23 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 18;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
 
@@ -590,7 +592,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 24 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 20;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
     }
@@ -630,7 +632,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 20;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         assertEquals(expectedStats,
                 mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX));
 
@@ -642,7 +644,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 20;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         assertEquals(expectedStats,
                 mQuotaController.getExecutionStatsLocked(0, "com.android.test", FREQUENT_INDEX));
 
@@ -654,7 +656,7 @@
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInMaxPeriod = 20;
         expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
-                + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                + mQcConstants.IN_QUOTA_BUFFER_MS;
         assertEquals(expectedStats,
                 mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX));
     }
@@ -685,8 +687,8 @@
         // Advance clock so that the working stats shouldn't be the same.
         advanceElapsedClock(MINUTE_IN_MILLIS);
         // Change frequent bucket size so that the stats need to be recalculated.
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS;
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS;
+        mQcConstants.updateConstants();
 
         ExecutionStats expectedStats = new ExecutionStats();
         expectedStats.windowSizeMs = originalStatsActive.windowSizeMs;
@@ -778,7 +780,7 @@
         setStandbyBucket(ACTIVE_INDEX);
         assertEquals(7 * MINUTE_IN_MILLIS,
                 mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
-        assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
+        assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
                 mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
@@ -901,7 +903,7 @@
     public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() {
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+        final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME;
         mQuotaController.saveTimingSession(0, "com.android.test.spam",
                 createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
         mQuotaController.saveTimingSession(0, "com.android.test.spam",
@@ -936,7 +938,7 @@
     public void testIsWithinQuotaLocked_OverDuration_OverJobCount() {
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+        final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME;
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
         mQuotaController.saveTimingSession(0, "com.android.test",
@@ -1098,8 +1100,7 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         // Test with timing sessions out of window but still under max execution limit.
         final long expectedAlarmTime =
-                (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - 18 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1));
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -1156,8 +1157,7 @@
         final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
         // Counting backwards, the quota will come back one minute before the end.
         final long expectedAlarmTime =
-                end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
                 new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1));
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1207,8 +1207,7 @@
 
         // Test with timing sessions in window but still in quota.
         final long start = now - (6 * HOUR_IN_MILLIS);
-        final long expectedAlarmTime =
-                start + 8 * HOUR_IN_MILLIS + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+        final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1262,7 +1261,7 @@
         // needs to be excluded.
         final long expectedAlarmTime =
                 start + MINUTE_IN_MILLIS + 24 * HOUR_IN_MILLIS
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1324,21 +1323,21 @@
         // And down from there.
         final long expectedWorkingAlarmTime =
                 outOfQuotaTime + (2 * HOUR_IN_MILLIS)
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX);
         inOrder.verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
 
         final long expectedFrequentAlarmTime =
                 outOfQuotaTime + (8 * HOUR_IN_MILLIS)
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX);
         inOrder.verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
 
         final long expectedRareAlarmTime =
                 outOfQuotaTime + (24 * HOUR_IN_MILLIS)
-                        + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX);
         inOrder.verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
@@ -1365,7 +1364,7 @@
         ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
                 SOURCE_PACKAGE, standbyBucket);
         stats.jobCountInAllowedTime =
-                mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME + 2;
+                mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME + 2;
 
         // Invalid time in the past, so the count shouldn't be used.
         stats.jobCountExpirationTimeElapsed =
@@ -1400,8 +1399,8 @@
     @Test
     public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedBufferSize() {
         // Make sure any new value is used correctly.
-        mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2;
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.IN_QUOTA_BUFFER_MS *= 2;
+        mQcConstants.updateConstants();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
         mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1410,8 +1409,8 @@
     @Test
     public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedAllowedTime() {
         // Make sure any new value is used correctly.
-        mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2;
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2;
+        mQcConstants.updateConstants();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
         mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1420,8 +1419,8 @@
     @Test
     public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedMaxTime() {
         // Make sure any new value is used correctly.
-        mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2;
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.MAX_EXECUTION_TIME_MS /= 2;
+        mQcConstants.updateConstants();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
         mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1430,10 +1429,10 @@
     @Test
     public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedEverything() {
         // Make sure any new value is used correctly.
-        mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2;
-        mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2;
-        mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2;
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.IN_QUOTA_BUFFER_MS *= 2;
+        mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2;
+        mQcConstants.MAX_EXECUTION_TIME_MS /= 2;
+        mQcConstants.updateConstants();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
         mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
         runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1448,9 +1447,8 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         // Working set window size is 2 hours.
         final int standbyBucket = WORKING_INDEX;
-        final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2;
-        final long remainingTimeMs =
-                mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS - contributionMs;
+        final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
+        final long remainingTimeMs = mQcConstants.ALLOWED_TIME_PER_PERIOD_MS - contributionMs;
 
         // Session straddles edge of bucket window. Only the contribution should be counted towards
         // the quota.
@@ -1462,7 +1460,7 @@
         // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
         // is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
         final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS
-                + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs);
+                + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
         mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
                 standbyBucket);
         verify(mAlarmManager, times(1))
@@ -1479,9 +1477,8 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         // Working set window size is 2 hours.
         final int standbyBucket = WORKING_INDEX;
-        final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2;
-        final long remainingTimeMs =
-                mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - contributionMs;
+        final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
+        final long remainingTimeMs = mQcConstants.MAX_EXECUTION_TIME_MS - contributionMs;
 
         // Session straddles edge of 24 hour window. Only the contribution should be counted towards
         // the quota.
@@ -1493,9 +1490,8 @@
         // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
         // is 24 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
         final long expectedAlarmTime = now - 20 * HOUR_IN_MILLIS
-                //+ mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS
                 + 24 * HOUR_IN_MILLIS
-                + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs);
+                + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
         mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
                 standbyBucket);
         verify(mAlarmManager, times(1))
@@ -1515,12 +1511,12 @@
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
 
-        mConstants.USE_HEARTBEATS = true;
+        mJsConstants.USE_HEARTBEATS = true;
         mQuotaController.onConstantsUpdatedLocked();
         Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
         assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
 
-        mConstants.USE_HEARTBEATS = false;
+        mJsConstants.USE_HEARTBEATS = false;
         mQuotaController.onConstantsUpdatedLocked();
         Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
         assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
@@ -1528,20 +1524,20 @@
 
     @Test
     public void testConstantsUpdating_ValidValues() {
-        mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = 5000;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 4000;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 3000;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 2000;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 500;
+        mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
+        mQcConstants.IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
+        mQcConstants.MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS;
+        mQcConstants.MAX_JOB_COUNT_ACTIVE = 5000;
+        mQcConstants.MAX_JOB_COUNT_WORKING = 4000;
+        mQcConstants.MAX_JOB_COUNT_FREQUENT = 3000;
+        mQcConstants.MAX_JOB_COUNT_RARE = 2000;
+        mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 500;
 
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.updateConstants();
 
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -1561,20 +1557,20 @@
     @Test
     public void testConstantsUpdating_InvalidValues() {
         // Test negatives/too low.
-        mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = -1;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 1;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 1;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 1;
-        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 0;
+        mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS;
+        mQcConstants.MAX_JOB_COUNT_ACTIVE = -1;
+        mQcConstants.MAX_JOB_COUNT_WORKING = 1;
+        mQcConstants.MAX_JOB_COUNT_FREQUENT = 1;
+        mQcConstants.MAX_JOB_COUNT_RARE = 1;
+        mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 0;
 
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.updateConstants();
 
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -1590,15 +1586,15 @@
         assertEquals(100, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]);
 
         // Test larger than a day. Controller should cap at one day.
-        mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS;
-        mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS;
+        mQcConstants.MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS;
 
-        mQuotaController.onConstantsUpdatedLocked();
+        mQcConstants.updateConstants();
 
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2219,7 +2215,7 @@
         verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
 
         // Ran jobs up to the job limit. All of them should be allowed to run.
-        for (int i = 0; i < mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) {
+        for (int i = 0; i < mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) {
             JobStatus job = createJobStatus("testStartAlarmScheduled_JobCount_AllowedTime", i);
             mQuotaController.maybeStartTrackingJobLocked(job, null);
             assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
@@ -2240,7 +2236,7 @@
         ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
                 SOURCE_PACKAGE, standbyBucket);
         final long expectedWorkingAlarmTime =
-                stats.jobCountExpirationTimeElapsed + mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
+                stats.jobCountExpirationTimeElapsed + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS;
         verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
index 494677d..19369db 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
@@ -39,6 +39,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
+import android.os.Looper;
 import android.os.SystemClock;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -70,7 +71,7 @@
     private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
     private static final int SOURCE_USER_ID = 0;
 
-    private Constants mConstants;
+    private TimeController.TcConstants mConstants;
     private TimeController mTimeController;
 
     private MockitoSession mMockingSession;
@@ -88,14 +89,13 @@
                 .strictness(Strictness.LENIENT)
                 .mockStatic(LocalServices.class)
                 .startMocking();
-        // Use default constants for now.
-        mConstants = new Constants();
 
         // Called in StateController constructor.
         when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
         when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
-        when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
+        when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class));
         // Called in TimeController constructor.
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
         // Used in JobStatus.
         doReturn(mock(PackageManagerInternal.class))
@@ -111,6 +111,7 @@
 
         // Initialize real objects.
         mTimeController = new TimeController(mJobSchedulerService);
+        mConstants = mTimeController.getTcConstants();
         spyOn(mTimeController);
     }
 
@@ -159,7 +160,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayInOrder_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+        mConstants.SKIP_NOT_READY_JOBS = false;
         mTimeController.onConstantsUpdatedLocked();
 
         runTestMaybeStartTrackingJobLocked_DelayInOrder();
@@ -167,7 +168,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -201,7 +202,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
@@ -235,7 +236,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayReverseOrder_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+        mConstants.SKIP_NOT_READY_JOBS = false;
         mTimeController.onConstantsUpdatedLocked();
 
         runTestMaybeStartTrackingJobLocked_DelayReverseOrder();
@@ -243,7 +244,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -279,7 +280,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
@@ -315,7 +316,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineInOrder_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+        mConstants.SKIP_NOT_READY_JOBS = false;
         mTimeController.onConstantsUpdatedLocked();
 
         runTestMaybeStartTrackingJobLocked_DeadlineInOrder();
@@ -323,7 +324,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -357,7 +358,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
@@ -391,7 +392,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+        mConstants.SKIP_NOT_READY_JOBS = false;
         mTimeController.onConstantsUpdatedLocked();
 
         runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder();
@@ -399,7 +400,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -438,7 +439,7 @@
 
     @Test
     public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        mConstants.SKIP_NOT_READY_JOBS = true;
         mTimeController.onConstantsUpdatedLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
@@ -493,8 +494,8 @@
                 .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
 
         // Starting off with the skipping off, we should still set an alarm for the earlier job.
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = false;
+        mTimeController.recheckAlarmsLocked();
         InOrder inOrder = inOrder(mAlarmManager);
 
         mTimeController.maybeStartTrackingJobLocked(jobEarliest, null);
@@ -504,16 +505,16 @@
                         eq(TAG_DEADLINE), any(), any(), any());
 
         // Turn it on, use alarm for later job.
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
 
         inOrder.verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DEADLINE),
                         any(), any(), any());
 
         // Back off, use alarm for earlier job.
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = false;
+        mTimeController.recheckAlarmsLocked();
 
         inOrder.verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
@@ -522,16 +523,16 @@
 
     @Test
     public void testCheckExpiredDelaysAndResetAlarm_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = false;
+        mTimeController.recheckAlarmsLocked();
 
         runTestCheckExpiredDelaysAndResetAlarm();
     }
 
     @Test
     public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
@@ -589,8 +590,8 @@
 
     @Test
     public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testCheckExpiredDelaysAndResetAlarm",
@@ -639,16 +640,16 @@
 
     @Test
     public void testCheckExpiredDeadlinesAndResetAlarm_NoSkipping() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = false;
+        mTimeController.recheckAlarmsLocked();
 
         runTestCheckExpiredDeadlinesAndResetAlarm();
     }
 
     @Test
     public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_AllReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
 
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
@@ -706,8 +707,8 @@
 
     @Test
     public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_SomeNotReady() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testCheckExpiredDeadlinesAndResetAlarm",
@@ -756,8 +757,8 @@
 
     @Test
     public void testEvaluateStateLocked_SkippingOff() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = false;
+        mTimeController.recheckAlarmsLocked();
         JobStatus job = createJobStatus("testEvaluateStateLocked_SkippingOff",
                 createJob().setOverrideDeadline(HOUR_IN_MILLIS));
 
@@ -768,8 +769,8 @@
 
     @Test
     public void testEvaluateStateLocked_SkippingOn_Delay() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay",
@@ -827,8 +828,8 @@
 
     @Test
     public void testEvaluateStateLocked_SkippingOn_Deadline() {
-        mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+        mConstants.SKIP_NOT_READY_JOBS = true;
+        mTimeController.recheckAlarmsLocked();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline",
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
index eb90295..dae3d30 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
@@ -137,7 +137,6 @@
             return mKeyValueMap.get(getKey(namespace, name));
         }).when(() -> DeviceConfig.getProperty(anyString(), anyString()));
 
-
         return new TestWatcher() {
             @Override
             protected void succeeded(Description description) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index bac8414..7a20af4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -329,6 +329,31 @@
         assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
     }
 
+    @Test
+    public void setPlatformKeyGenerationId_invalidatesExistingKeysForUser() {
+        int userId = 42;
+        int generationId = 110;
+        int uid = 1009;
+        int status = 120;
+        String alias = "test";
+        byte[] nonce = getUtf8Bytes("nonce");
+        byte[] keyMaterial = getUtf8Bytes("keymaterial");
+        byte[] keyMetadata = null;
+
+        WrappedKey wrappedKey =
+                new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, status);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+        WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+        assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
+
+        mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
+
+        retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+        assertThat(retrievedKey.getRecoveryStatus())
+                .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+    }
+
 
     @Test
     public void removeUserFromAllTables_removesData() throws Exception {
@@ -439,7 +464,7 @@
     }
 
     @Test
-    public void testInvalidateKeysWithOldGenerationId_withSingleKey() {
+    public void testInvalidateKeysForUser_withSingleKey() {
         int userId = 12;
         int uid = 1009;
         int generationId = 6;
@@ -458,7 +483,7 @@
         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
 
         mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
-        mRecoverableKeyStoreDb.invalidateKeysWithOldGenerationId(userId, generationId + 1);
+        mRecoverableKeyStoreDb.invalidateKeysForUser(userId);
 
         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
         assertThat(retrievedKey.getRecoveryStatus())
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 0c2ce61..385748c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -166,6 +167,25 @@
         verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
     }
 
+    @Test
+    public void testShouldAnimateWhenNoCancelWithDeferredScreenshot() {
+        mWm.setRecentsAnimationController(mController);
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+        appWindow.addWindow(win1);
+        assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+        assertEquals(appWindow.findMainWindow(), win1);
+
+        mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+        // Assume appWindow transition should animate when no
+        // IRecentsAnimationController#setCancelWithDeferredScreenshot called.
+        assertFalse(mController.shouldCancelWithDeferredScreenshot());
+        assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 12b20ef..64c1830 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -419,7 +419,8 @@
         // settings to individually disable the new restrictions for privileged, preloaded
         // non-privileged, and non-preinstalled apps.
         if (!isIdentifierCheckDisabled() && (
-                (!isPreinstalled && !relax3PDeviceIdentifierCheck)
+                (isPrivApp && !relaxPrivDeviceIdentifierCheck)
+                        || (!isPreinstalled && !relax3PDeviceIdentifierCheck)
                         || (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) {
             // The current package should only be reported in StatsLog if it has not previously been
             // reported for the currently invoked device identifier method.
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 13e737e..eb19361 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -18,25 +18,27 @@
 
 import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
 
-import static com.android.server.PackageWatchdog.MonitoredPackage;
-import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.Manifest;
 import android.content.Context;
 import android.content.pm.VersionedPackage;
 import android.os.Handler;
 import android.os.test.TestLooper;
+import android.provider.DeviceConfig;
 import android.util.AtomicFile;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.server.PackageWatchdog.MonitoredPackage;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
 import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -73,8 +75,13 @@
     public void setUp() throws Exception {
         new File(InstrumentationRegistry.getContext().getFilesDir(),
                 "package-watchdog.xml").delete();
+        adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG);
         mTestLooper = new TestLooper();
-        mTestLooper.startAutoDispatch();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        dropShellPermissions();
     }
 
     /**
@@ -204,7 +211,7 @@
         // Verify random observer not saved returns null
         assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3)));
 
-        // Then regiser observer1
+        // Then register observer1
         watchdog2.registerHealthObserver(observer1);
         watchdog2.registerHealthObserver(observer2);
 
@@ -231,7 +238,7 @@
         watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
 
         // Then fail APP_A below the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
 
@@ -258,7 +265,7 @@
         watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION);
 
         // Then fail APP_C (not observed) above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)));
         }
 
@@ -292,7 +299,7 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
 
         // Then fail APP_A (different version) above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(
                             new VersionedPackage(APP_A, differentVersionCode)));
         }
@@ -331,7 +338,7 @@
                 SHORT_DURATION);
 
         // Then fail all apps above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
                     new VersionedPackage(APP_B, VERSION_CODE),
                     new VersionedPackage(APP_C, VERSION_CODE),
@@ -384,7 +391,7 @@
         watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
 
         // Then fail APP_A above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
         // Run handler so package failures are dispatched to observers
@@ -401,7 +408,7 @@
         observerSecond.mFailedPackages.clear();
 
         // Then fail APP_A again above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
         // Run handler so package failures are dispatched to observers
@@ -418,7 +425,7 @@
         observerSecond.mFailedPackages.clear();
 
         // Then fail APP_A again above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
         // Run handler so package failures are dispatched to observers
@@ -435,7 +442,7 @@
         observerSecond.mFailedPackages.clear();
 
         // Then fail APP_A again above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
         // Run handler so package failures are dispatched to observers
@@ -462,7 +469,7 @@
         watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
 
         // Then fail APP_A above the threshold
-        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+        for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
             watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
         }
 
@@ -539,6 +546,10 @@
      */
     @Test
     public void testExplicitHealthCheckStateChanges() throws Exception {
+        adoptShellPermissions(
+                Manifest.permission.WRITE_DEVICE_CONFIG,
+                Manifest.permission.READ_DEVICE_CONFIG);
+
         TestController controller = new TestController();
         PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
         TestObserver observer = new TestObserver(OBSERVER_NAME_1,
@@ -559,7 +570,7 @@
         assertEquals(APP_B, requestedPackages.get(1));
 
         // Disable explicit health checks (marks APP_A and APP_B as passed)
-        watchdog.setExplicitHealthCheckEnabled(false);
+        setExplicitHealthCheckEnabled(false);
 
         // Run handler so requests/cancellations are dispatched to the controller
         mTestLooper.dispatchAll();
@@ -575,7 +586,7 @@
         assertEquals(0, observer.mFailedPackages.size());
 
         // Re-enable explicit health checks
-        watchdog.setExplicitHealthCheckEnabled(true);
+        setExplicitHealthCheckEnabled(true);
 
         // Run handler so requests/cancellations are dispatched to the controller
         mTestLooper.dispatchAll();
@@ -643,11 +654,13 @@
     /** Tests {@link MonitoredPackage} health check state transitions. */
     @Test
     public void testPackageHealthCheckStateTransitions() {
-        MonitoredPackage m1 = new MonitoredPackage(APP_A, LONG_DURATION,
+        TestController controller = new TestController();
+        PackageWatchdog wd = createWatchdog(controller, true /* withPackagesReady */);
+        MonitoredPackage m1 = wd.new MonitoredPackage(APP_A, LONG_DURATION,
                 false /* hasPassedHealthCheck */);
-        MonitoredPackage m2 = new MonitoredPackage(APP_B, LONG_DURATION, false);
-        MonitoredPackage m3 = new MonitoredPackage(APP_C, LONG_DURATION, false);
-        MonitoredPackage m4 = new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+        MonitoredPackage m2 = wd.new MonitoredPackage(APP_B, LONG_DURATION, false);
+        MonitoredPackage m3 = wd.new MonitoredPackage(APP_C, LONG_DURATION, false);
+        MonitoredPackage m4 = wd.new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
 
         // Verify transition: inactive -> active -> passed
         // Verify initially inactive
@@ -683,6 +696,32 @@
         assertEquals(MonitoredPackage.STATE_PASSED, m4.handleElapsedTimeLocked(LONG_DURATION));
     }
 
+    private void adoptShellPermissions(String... permissions) {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(permissions);
+    }
+
+    private void dropShellPermissions() {
+        InstrumentationRegistry
+                .getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    private void setExplicitHealthCheckEnabled(boolean enabled) {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+                PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+                Boolean.toString(enabled), /*makeDefault*/false);
+        //give time for DeviceConfig to broadcast the property value change
+        try {
+            Thread.sleep(SHORT_DURATION);
+        } catch (InterruptedException e) {
+            fail("Thread.sleep unexpectedly failed!");
+        }
+    }
+
     private PackageWatchdog createWatchdog() {
         return createWatchdog(new TestController(), true /* withPackagesReady */);
     }