Merge "[base] Migrate deprecated GL GrBackendRenderTarget constructor" into main
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7be4b15..0255860 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2876,16 +2876,25 @@
         final SuspendDialogInfo dialogInfo = !TextUtils.isEmpty(dialogMessage)
                 ? new SuspendDialogInfo.Builder().setMessage(dialogMessage).build()
                 : null;
-        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras, dialogInfo);
+        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras,
+                dialogInfo, 0);
     }
 
     @Override
     public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
             PersistableBundle appExtras, PersistableBundle launcherExtras,
             SuspendDialogInfo dialogInfo) {
+        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras,
+                dialogInfo, 0);
+    }
+
+    @Override
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras,
+            SuspendDialogInfo dialogInfo, int flags) {
         try {
             return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
-                    launcherExtras, dialogInfo, mContext.getOpPackageName(),
+                    launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
                     getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c11a8fc..5ef7b11 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -323,6 +323,7 @@
             // Make sure no flag uses the sign bit (most significant bit) of the long integer,
             // to avoid future confusion.
             BIND_BYPASS_USER_NETWORK_RESTRICTIONS,
+            BIND_FILTER_OUT_QUARANTINED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BindServiceFlagsLongBits {}
@@ -697,6 +698,13 @@
      */
     public static final long BIND_BYPASS_USER_NETWORK_RESTRICTIONS = 0x1_0000_0000L;
 
+    /**
+     * Flag for {@link #bindService}.
+     *
+     * @hide
+     */
+    public static final long BIND_FILTER_OUT_QUARANTINED_COMPONENTS = 0x2_0000_0000L;
+
 
     /**
      * These bind flags reduce the strength of the binding such that we shouldn't
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fe108a5..afeb3d29 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6383,6 +6383,15 @@
             "android.intent.extra.changed_uid_list";
 
     /**
+     * This field is part of
+     * {@link android.content.Intent#ACTION_PACKAGES_SUSPENDED},
+     * and only present if the packages were quarantined.
+     * @hide
+     */
+    public static final String EXTRA_QUARANTINED =
+            "android.intent.extra.quarantined";
+
+    /**
      * An integer denoting a bitwise combination of restrictions set on distracting packages via
      * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
      *
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7c9ccba..c5585af 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -298,7 +298,7 @@
 
     String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
             in PersistableBundle appExtras, in PersistableBundle launcherExtras,
-            in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
+            in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);
 
     String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9f14c97..885e67e1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -834,6 +834,7 @@
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
+            FILTER_OUT_QUARANTINED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ComponentInfoFlagsBits {}
@@ -857,7 +858,8 @@
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
-            MATCH_CLONE_PROFILE
+            MATCH_CLONE_PROFILE,
+            FILTER_OUT_QUARANTINED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResolveInfoFlagsBits {}
@@ -1233,6 +1235,11 @@
     public static final long GET_ATTRIBUTIONS_LONG = 0x80000000L;
 
     /**
+     * @hide
+     */
+    public static final long FILTER_OUT_QUARANTINED_COMPONENTS = 0x100000000L;
+
+    /**
      * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
      * resolving an intent that matches the {@code CrossProfileIntentFilter},
      * the current profile will be skipped. Only activities in the target user
@@ -1685,7 +1692,7 @@
     /** @hide */
     @IntDef(flag = true, value = {
             DONT_KILL_APP,
-            SYNCHRONOUS
+            SYNCHRONOUS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EnabledFlags {}
@@ -1708,6 +1715,24 @@
     public static final int SYNCHRONOUS = 0x00000002;
 
     /** @hide */
+    @IntDef(flag = true, value = {
+            FLAG_SUSPEND_QUARANTINED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SuspendedFlags {}
+
+    /**
+     * Flag parameter {@link #setPackagesSuspended(String[], boolean, PersistableBundle,
+     * PersistableBundle, android.content.pm.SuspendDialogInfo, int)}:
+     * Apps in this state not only appear suspended for all user visible purposes (eg, Launcher,
+     * ShareSheet), but also individual components of the app can behave as disabled depending on
+     * the importance of the calling app.
+     *
+     * @hide
+     */
+    public static final int FLAG_SUSPEND_QUARANTINED = 0x00000001;
+
+    /** @hide */
     @IntDef(prefix = { "INSTALL_REASON_" }, value = {
             INSTALL_REASON_UNKNOWN,
             INSTALL_REASON_POLICY,
@@ -9654,6 +9679,63 @@
     }
 
     /**
+     * Puts the given packages in a suspended state, where attempts at starting activities are
+     * denied.
+     *
+     * <p>The suspended application's notifications and all of its windows will be hidden, any
+     * of its started activities will be stopped and it won't be able to ring the device.
+     * It doesn't remove the data or the actual package file.
+     *
+     * <p>When the user tries to launch a suspended app, a system dialog alerting them that the app
+     * is suspended will be shown instead.
+     * The caller can optionally customize the dialog by passing a {@link SuspendDialogInfo} object
+     * to this API. This dialog will have a button that starts the
+     * {@link Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} intent if the suspending app declares an
+     * activity which handles this action.
+     *
+     * <p>The packages being suspended must already be installed. If a package is uninstalled, it
+     * will no longer be suspended.
+     *
+     * <p>Optionally, the suspending app can provide extra information in the form of
+     * {@link PersistableBundle} objects to be shared with the apps being suspended and the
+     * launcher to support customization that they might need to handle the suspended state.
+     *
+     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API except for
+     * device owner and profile owner.
+     *
+     * @param packageNames The names of the packages to set the suspended status.
+     * @param suspended If set to {@code true}, the packages will be suspended, if set to
+     * {@code false}, the packages will be unsuspended.
+     * @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
+     *                  which will be shared with the apps being suspended. Ignored if
+     *                  {@code suspended} is false.
+     * @param launcherExtras An optional {@link PersistableBundle} that the suspending app can
+     *                       provide which will be shared with the launcher. Ignored if
+     *                       {@code suspended} is false.
+     * @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
+     *                   should be shown to the user when they try to launch a suspended app.
+     *                   Ignored if {@code suspended} is false.
+     * @param flags Optional behavior flags.
+     *
+     * @return an array of package names for which the suspended status could not be set as
+     * requested in this method. Returns {@code null} if {@code packageNames} was {@code null}.
+     *
+     * @see #isPackageSuspended
+     * @see SuspendDialogInfo
+     * @see SuspendDialogInfo.Builder
+     * @see Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS
+     *
+     * @hide
+     */
+    @RequiresPermission(value=Manifest.permission.SUSPEND_APPS, conditional=true)
+    @Nullable
+    public String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended,
+            @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
+            @Nullable SuspendDialogInfo dialogInfo, @SuspendedFlags int flags) {
+        throw new UnsupportedOperationException("setPackagesSuspended not implemented");
+    }
+
+    /**
      * Returns any packages in a given set of packages that cannot be suspended via a call to {@link
      * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
      * SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 048289f..9387ae1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8005,7 +8005,7 @@
             ai.enabled = true;
         } else if (state.getEnabledState()
                 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-            ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
+            ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
         } else if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                 || state.getEnabledState()
                 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7a96fd2..e1de05b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -6948,6 +6948,7 @@
             // something is going to start.
             opts.setPendingIntentBackgroundActivityStartMode(
                     ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+            opts.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
             return Pair.create(intent, opts);
         }
     }
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index a5e775a..1e0b2a0 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -297,7 +297,7 @@
                         final IPackageManager ipm = AppGlobals.getPackageManager();
                         try {
                             final String[] errored = ipm.setPackagesSuspendedAsUser(
-                                    new String[]{mSuspendedPackage}, false, null, null, null,
+                                    new String[]{mSuspendedPackage}, false, null, null, null, 0,
                                     mSuspendingPackage, mUserId);
                             if (ArrayUtils.contains(errored, mSuspendedPackage)) {
                                 Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 58106c0..bb67bbc3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -441,7 +441,7 @@
                                 String.valueOf(Global.Wearable.TETHERED_CONFIG_TETHERED)
                         }));
         VALIDATORS.put(Global.Wearable.PHONE_SWITCHING_SUPPORTED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Global.Wearable.WEAR_LAUNCHER_UI_MODE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.WEAR_LAUNCHER_UI_MODE, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media.xml b/packages/SystemUI/res/drawable-television/ic_volume_media.xml
deleted file mode 100644
index 6a368d5..0000000
--- a/packages/SystemUI/res/drawable-television/ic_volume_media.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/tv_volume_icons_size"
-    android:height="@dimen/tv_volume_icons_size"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/tv_volume_dialog_accent"
-        android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM10,8.83v6.34L7.83,13L5,13v-2h2.83L10,8.83zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77 0,-4.28 -2.99,-7.86 -7,-8.77z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml
deleted file mode 100644
index 6eb944f..0000000
--- a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/tv_volume_icons_size"
-    android:height="@dimen/tv_volume_icons_size"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <group android:translateX="-2">
-        <path
-            android:fillColor="@color/tv_volume_dialog_accent"
-            android:pathData="M16,7.97v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02 0,-1.77 -1.02,-3.29 -2.5,-4.03zM5,9v6h4l5,5L14,4L9,9L5,9zM12,8.83v6.34L9.83,13L7,13v-2h2.83L12,8.83z"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml
deleted file mode 100644
index b683089..0000000
--- a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/tv_volume_icons_size"
-    android:height="@dimen/tv_volume_icons_size"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <group android:translateX="-4">
-        <path
-            android:fillColor="@color/tv_volume_dialog_accent"
-            android:pathData="M14,8.83v6.34L11.83,13H9v-2h2.83L14,8.83M16,4l-5,5H7v6h4l5,5V4z"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml
deleted file mode 100644
index 7a44aa6..0000000
--- a/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/tv_volume_icons_size"
-    android:height="@dimen/tv_volume_icons_size"
-    android:viewportHeight="24"
-    android:viewportWidth="24">
-    <path
-        android:fillColor="@color/tv_volume_dialog_accent"
-        android:pathData="M4.34,2.93L2.93,4.34 7.29,8.7 7,9L3,9v6h4l5,5v-6.59l4.18,4.18c-0.65,0.49 -1.38,0.88 -2.18,1.11v2.06c1.34,-0.3 2.57,-0.92 3.61,-1.75l2.05,2.05 1.41,-1.41L4.34,2.93zM10,15.17L7.83,13L5,13v-2h2.83l0.88,-0.88L10,11.41v3.76zM19,12c0,0.82 -0.15,1.61 -0.41,2.34l1.53,1.53c0.56,-1.17 0.88,-2.48 0.88,-3.87 0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM12,4l-1.88,1.88L12,7.76zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v1.79l2.48,2.48c0.01,-0.08 0.02,-0.16 0.02,-0.24z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable-television/volume_row_seekbar.xml b/packages/SystemUI/res/drawable-television/volume_row_seekbar.xml
deleted file mode 100644
index e49fc15..0000000
--- a/packages/SystemUI/res/drawable-television/volume_row_seekbar.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2021 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
-            android:paddingMode="stack">
-    <item android:id="@android:id/background"
-        android:gravity="center_vertical|fill_horizontal">
-        <layer-list>
-            <item android:id="@+id/volume_seekbar_background_solid">
-                <shape>
-                    <size android:height="@dimen/volume_dialog_slider_width" />
-                    <solid android:color="@color/tv_volume_dialog_seek_bar_background"/>
-                    <corners android:radius="@dimen/volume_dialog_slider_corner_radius" />
-                </shape>
-            </item>
-        </layer-list>
-    </item>
-    <item android:id="@android:id/progress"
-          android:gravity="center_vertical|fill_horizontal">
-            <com.android.systemui.util.RoundedCornerProgressDrawable
-                android:drawable="@drawable/volume_row_seekbar_progress"
-            />
-    </item>
-</layer-list>
diff --git a/packages/SystemUI/res/drawable-television/volume_row_seekbar_progress.xml b/packages/SystemUI/res/drawable-television/volume_row_seekbar_progress.xml
deleted file mode 100644
index bce193a..0000000
--- a/packages/SystemUI/res/drawable-television/volume_row_seekbar_progress.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!-- Progress drawable for volume row SeekBars. This is the accent-colored round rect that moves up
-     and down as the progress value changes. -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:id="@+id/volume_seekbar_progress_solid">
-        <shape android:shape="rectangle">
-            <size android:height="@dimen/volume_dialog_slider_width"/>
-            <solid android:color="@color/tv_volume_dialog_seek_bar_fill" />
-            <corners android:radius="@dimen/volume_dialog_slider_width" />
-        </shape>
-    </item>
-</layer-list>
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a4d72b1..66a77a3 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -191,6 +191,7 @@
         "apache-commons-math",
         "power_optimization_flags_lib",
         "notification_flags_lib",
+        "pm_flags_lib",
     ],
     javac_shard_size: 50,
     javacflags: [
@@ -240,4 +241,4 @@
 prebuilt_etc {
     name: "protolog.conf.json.gz",
     src: ":services.core.json.gz",
-}
\ No newline at end of file
+}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index fc51e2e..557e4ac 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1374,7 +1374,7 @@
      * and the package should get out of stopped state and be enabled.
      */
     public abstract void notifyComponentUsed(@NonNull String packageName,
-            @UserIdInt int userId, @NonNull String recentCallingPackage);
+            @UserIdInt int userId, @NonNull String recentCallingPackage, @NonNull String debugInfo);
 
     /** @deprecated For legacy shell command only. */
     @Deprecated
@@ -1403,4 +1403,10 @@
      */
     public abstract int[] getDistractingPackageRestrictionsAsUser(
             @NonNull String[] packageNames, int userId);
+
+    /**
+     * Checks if package is quarantined for a specific user.
+     */
+    public abstract boolean isPackageQuarantined(@NonNull String packageName,
+            @UserIdInt int userId);
 }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d398260..330742a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5309,11 +5309,12 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
             }
-            int flags = Context.BIND_AUTO_CREATE;
+            long flags = Context.BIND_FILTER_OUT_QUARANTINED_COMPONENTS | Context.BIND_AUTO_CREATE;
             if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
                 flags |= Context.BIND_ALLOW_INSTANT;
             }
-            if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
+            if (!mContext.bindServiceAsUser(intent, this, Context.BindServiceFlags.of(flags),
+                    UserHandle.of(mAccounts.userId))) {
                 Log.w(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
                 // Perform unbind as per documentation at Context.bindServiceAsUser
                 mContext.unbindService(this);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cb246f6..93fe0c9 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3601,6 +3601,8 @@
                 || (flags & Context.BIND_EXTERNAL_SERVICE_LONG) != 0;
         final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
         final boolean inSharedIsolatedProcess = (flags & Context.BIND_SHARED_ISOLATED_PROCESS) != 0;
+        final boolean filterOutQuarantined =
+                (flags & Context.BIND_FILTER_OUT_QUARANTINED_COMPONENTS) != 0;
 
         ProcessRecord attributedApp = null;
         if (sdkSandboxClientAppUid > 0) {
@@ -3610,7 +3612,7 @@
                 isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
                 resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
                 isBindExternal, allowInstant, null /* fgsDelegateOptions */,
-                inSharedIsolatedProcess);
+                inSharedIsolatedProcess, filterOutQuarantined);
         if (res == null) {
             return 0;
         }
@@ -4119,6 +4121,20 @@
             boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
             boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions,
             boolean inSharedIsolatedProcess) {
+        return retrieveServiceLocked(service, instanceName, isSdkSandboxService,
+                sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, callingPackage,
+                callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
+                allowInstant, fgsDelegateOptions, inSharedIsolatedProcess,
+                false /* filterOutQuarantined */);
+    }
+
+    private ServiceLookupResult retrieveServiceLocked(Intent service,
+            String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
+            String sdkSandboxClientAppPackage, String resolvedType,
+            String callingPackage, int callingPid, int callingUid, int userId,
+            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
+            boolean allowInstant, ForegroundServiceDelegationOptions fgsDelegateOptions,
+            boolean inSharedIsolatedProcess, boolean filterOutQuarantined) {
         if (isSdkSandboxService && instanceName == null) {
             throw new IllegalArgumentException("No instanceName provided for sdk sandbox process");
         }
@@ -4235,11 +4251,14 @@
 
         if (r == null) {
             try {
-                int flags = ActivityManagerService.STOCK_PM_FLAGS
+                long flags = ActivityManagerService.STOCK_PM_FLAGS
                         | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
                 if (allowInstant) {
                     flags |= PackageManager.MATCH_INSTANT;
                 }
+                if (filterOutQuarantined) {
+                    flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+                }
                 // TODO: come back and remove this assumption to triage all services
                 ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service,
                         resolvedType, flags, userId, callingUid);
@@ -5118,7 +5137,7 @@
 
         try {
             mAm.mPackageManagerInt.notifyComponentUsed(
-                    r.packageName, r.userId, r.mRecentCallingPackage);
+                    r.packageName, r.userId, r.mRecentCallingPackage, r.toString());
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
                     + r.packageName + ": " + e);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4dc76db..c4816fb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -58,6 +58,7 @@
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_PERSISTENT;
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_SYSTEM;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
+import static android.content.pm.PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -14221,7 +14222,8 @@
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
             int callingUid, int[] users, int[] broadcastAllowList) {
         // TODO: come back and remove this assumption to triage all broadcasts
-        int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
+        long pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING
+                | FILTER_OUT_QUARANTINED_COMPONENTS;
 
         List<ResolveInfo> receivers = null;
         HashSet<ComponentName> singleUserReceivers = null;
@@ -14849,6 +14851,16 @@
 
                             mAtmInternal.onPackagesSuspendedChanged(packageNames, suspended,
                                     userIdExtra);
+
+                            final boolean quarantined = intent.getBooleanExtra(
+                                    Intent.EXTRA_QUARANTINED, false);
+                            if (suspended && quarantined && packageNames != null) {
+                                for (int i = 0; i < packageNames.length; i++) {
+                                    forceStopPackageLocked(packageNames[i], -1, false, true, true,
+                                            false, false, userId, "suspended");
+                                }
+                            }
+
                             break;
                     }
                     break;
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
index 6e93ce4..3fa6102 100644
--- a/services/core/java/com/android/server/am/ComponentAliasResolver.java
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -457,7 +457,7 @@
     @Nullable
     public Resolution<ResolveInfo> resolveReceiver(@NonNull Intent intent,
             @NonNull ResolveInfo receiver, @Nullable String resolvedType,
-            int packageFlags, int userId, int callingUid, boolean forSend) {
+            long packageFlags, int userId, int callingUid, boolean forSend) {
         // Resolve this alias.
         final Resolution<ComponentName> resolution = resolveComponentAlias(() ->
                 receiver.activityInfo.getComponentName());
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 65fd54a..4cc147f 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -509,7 +509,8 @@
                             checkTime(startTime,
                                     "getContentProviderImpl: before set stopped state");
                             mService.mPackageManagerInt.notifyComponentUsed(
-                                    cpr.appInfo.packageName, userId, callingPackage);
+                                    cpr.appInfo.packageName, userId, callingPackage,
+                                    cpr.toString());
                             checkTime(startTime, "getContentProviderImpl: after set stopped state");
                         } catch (IllegalArgumentException e) {
                             Slog.w(TAG, "Failed trying to unstop package "
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8a8e2af..70a1c91 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1531,7 +1531,11 @@
         sb.append("ServiceRecord{")
             .append(Integer.toHexString(System.identityHashCode(this)))
             .append(" u").append(userId)
-            .append(' ').append(shortInstanceName).append('}');
+            .append(' ').append(shortInstanceName);
+        if (mRecentCallingPackage != null) {
+            sb.append(" c:").append(mRecentCallingPackage);
+        }
+        sb.append('}');
         return stringName = sb.toString();
     }
 
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 86da39b..a17b3d5 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -97,7 +97,7 @@
  */
 public final class AppHibernationService extends SystemService {
     private static final String TAG = "AppHibernationService";
-    private static final int PACKAGE_MATCH_FLAGS =
+    private static final long PACKAGE_MATCH_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE
                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                     | PackageManager.MATCH_UNINSTALLED_PACKAGES
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3e31bd1..0aac7c2 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -220,8 +220,10 @@
     private static final int SYNC_OP_STATE_INVALID_SYNC_DISABLED = 5;
 
     /** Flags used when connecting to a sync adapter service */
-    private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
-            | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
+    private static final Context.BindServiceFlags SYNC_ADAPTER_CONNECTION_FLAGS =
+            Context.BindServiceFlags.of(
+                    Context.BIND_FILTER_OUT_QUARANTINED_COMPONENTS | Context.BIND_AUTO_CREATE
+                            | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT);
 
     /** Singleton instance. */
     @GuardedBy("SyncManager.class")
diff --git a/services/core/java/com/android/server/pm/Android.bp b/services/core/java/com/android/server/pm/Android.bp
new file mode 100644
index 0000000..89c0124
--- /dev/null
+++ b/services/core/java/com/android/server/pm/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "pm_flags",
+    package: "com.android.server.pm",
+    srcs: [
+        "*.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "pm_flags_lib",
+    aconfig_declarations: "pm_flags",
+}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 5b05b48..7d878ec 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -522,6 +522,7 @@
                 comp != null || pkgName != null /*onlyExposedExplicitly*/,
                 isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
                         flags));
+
         List<ResolveInfo> list = Collections.emptyList();
         boolean skipPostResolution = false;
         if (comp != null) {
@@ -643,6 +644,12 @@
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
                 false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
+
+        // Only if the query is coming from the system process,
+        // it should be allowed to match quarantined components
+        if (callingUid != Process.SYSTEM_UID) {
+            flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+        }
         Intent originalIntent = null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -4031,6 +4038,9 @@
         flags = updateFlagsForComponent(flags, userId);
         enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
                 false /* checkShell */, "get provider info");
+        if (callingUid != Process.SYSTEM_UID) {
+            flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+        }
         ParsedProvider p = mComponentResolver.getProvider(component);
         if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
@@ -4660,6 +4670,9 @@
             int callingUid) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId);
+        if (callingUid != Process.SYSTEM_UID) {
+            flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+        }
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(this, name, flags,
                 userId);
         boolean checkedGrants = false;
@@ -4772,6 +4785,13 @@
                 false /* checkShell */, "queryContentProviders");
         if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForComponent(flags, userId);
+
+        // Only if the service query is coming from the system process,
+        // it should be allowed to match quarantined components
+        if (callingUid != Process.SYSTEM_UID) {
+            flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+        }
+
         ArrayList<ProviderInfo> finalList = null;
         final List<ProviderInfo> matchList = mComponentResolver.queryProviders(this, processName,
                 metaDataKey, uid, flags, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 82587c5..6efd067 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -746,10 +746,18 @@
     }
 
     @Override
-    public void notifyComponentUsed(@NonNull String packageName,
-            @UserIdInt int userId, @NonNull String recentCallingPackage) {
+    public void notifyComponentUsed(@NonNull String packageName, @UserIdInt int userId,
+            @NonNull String recentCallingPackage, @NonNull String debugInfo) {
         mService.notifyComponentUsed(snapshot(), packageName, userId,
-                recentCallingPackage);
+                recentCallingPackage, debugInfo);
+    }
+
+    @Override
+    public boolean isPackageQuarantined(@NonNull String packageName,
+            @UserIdInt int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        return (packageState == null) ? false
+                : packageState.getUserStateOrDefault(userId).isQuarantined();
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6bcfcfe..6c0aeec 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4583,7 +4583,18 @@
     }
 
     void notifyComponentUsed(@NonNull Computer snapshot, @NonNull String packageName,
-            @UserIdInt int userId, @NonNull String recentCallingPackage) {
+            @UserIdInt int userId, @NonNull String recentCallingPackage,
+            @NonNull String debugInfo) {
+        synchronized (mLock) {
+            final PackageUserStateInternal userState = mSettings.getPackageLPr(
+                    packageName).getUserStateOrDefault(userId);
+            if (userState.isQuarantined()) {
+                Slog.i(TAG,
+                        "Component is quarantined+suspended but being used: "
+                                + packageName + " by " + recentCallingPackage + ", debugInfo: "
+                                + debugInfo);
+            }
+        }
         PackageManagerService.this
                 .setPackageStoppedState(snapshot, packageName, false /* stopped */,
                         userId);
@@ -6120,14 +6131,16 @@
         @Override
         public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
                 PersistableBundle appExtras, PersistableBundle launcherExtras,
-                SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
+                SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId) {
             final int callingUid = Binder.getCallingUid();
             final Computer snapshot = snapshotComputer();
             enforceCanSetPackagesSuspendedAsUser(snapshot, callingPackage, callingUid, userId,
                     "setPackagesSuspendedAsUser");
+            boolean quarantined = ((flags & PackageManager.FLAG_SUSPEND_QUARANTINED) != 0)
+                    && Flags.quarantinedEnabled();
             return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
                     appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid,
-                    false /* forQuietMode */);
+                    false /* forQuietMode */, quarantined);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index ce0e7ad..ceae1fe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -288,9 +288,11 @@
                 case "unhide":
                     return runSetHiddenSetting(false);
                 case "suspend":
-                    return runSuspend(true);
+                    return runSuspend(true, 0);
+                case "suspend-quarantine":
+                    return runSuspend(true, PackageManager.FLAG_SUSPEND_QUARANTINED);
                 case "unsuspend":
-                    return runSuspend(false);
+                    return runSuspend(false, 0);
                 case "set-distracting-restriction":
                     return runSetDistractingRestriction();
                 case "get-distracting-restriction":
@@ -2644,7 +2646,7 @@
         }
     }
 
-    private int runSuspend(boolean suspendedState) {
+    private int runSuspend(boolean suspendedState, int flags) {
         final PrintWriter pw = getOutPrintWriter();
         int userId = UserHandle.USER_SYSTEM;
         String dialogMessage = null;
@@ -2712,7 +2714,7 @@
             mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
                     suspendedState, ((appExtras.size() > 0) ? appExtras : null),
                     ((launcherExtras.size() > 0) ? launcherExtras : null),
-                    info, callingPackage, translatedUserId);
+                    info, flags, callingPackage, translatedUserId);
             for (int i = 0; i < packageNames.size(); i++) {
                 final String packageName = packageNames.get(i);
                 pw.println("Package " + packageName + " new suspended state: "
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index dee31ec..14693a6 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -937,8 +937,8 @@
                 otherState.isHidden(), otherState.getDistractionFlags(),
                 otherState.getSuspendParams() == null
                         ? null : otherState.getSuspendParams().untrackedStorage(),
-                otherState.isInstantApp(),
-                otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(),
+                otherState.isInstantApp(), otherState.isVirtualPreload(),
+                otherState.getLastDisableAppCaller(),
                 otherState.getEnabledComponentsNoCopy() == null
                         ? null : otherState.getEnabledComponentsNoCopy().untrackedStorage(),
                 otherState.getDisabledComponentsNoCopy() == null
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c6135e0..b6da462 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1918,9 +1918,9 @@
 
                         ArraySet<String> enabledComponents = null;
                         ArraySet<String> disabledComponents = null;
-                        PersistableBundle suspendedAppExtras = null;
-                        PersistableBundle suspendedLauncherExtras = null;
                         SuspendDialogInfo oldSuspendDialogInfo = null;
+                        PersistableBundle oldSuspendedAppExtras = null;
+                        PersistableBundle oldSuspendedLauncherExtras = null;
                         ArchiveState archiveState = null;
 
                         int packageDepth = parser.getDepth();
@@ -1939,16 +1939,17 @@
                                 case TAG_DISABLED_COMPONENTS:
                                     disabledComponents = readComponentsLPr(parser);
                                     break;
-                                case TAG_SUSPENDED_APP_EXTRAS:
-                                    suspendedAppExtras = PersistableBundle.restoreFromXml(parser);
-                                    break;
-                                case TAG_SUSPENDED_LAUNCHER_EXTRAS:
-                                    suspendedLauncherExtras = PersistableBundle.restoreFromXml(
-                                            parser);
-                                    break;
                                 case TAG_SUSPENDED_DIALOG_INFO:
                                     oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
                                     break;
+                                case TAG_SUSPENDED_APP_EXTRAS:
+                                    oldSuspendedAppExtras = PersistableBundle.restoreFromXml(
+                                            parser);
+                                    break;
+                                case TAG_SUSPENDED_LAUNCHER_EXTRAS:
+                                    oldSuspendedLauncherExtras = PersistableBundle.restoreFromXml(
+                                            parser);
+                                    break;
                                 case TAG_SUSPEND_PARAMS:
                                     final String suspendingPackage = parser.getAttributeValue(null,
                                             ATTR_SUSPENDING_PACKAGE);
@@ -1979,8 +1980,9 @@
                         if (suspended && suspendParamsMap == null) {
                             final SuspendParams suspendParams = new SuspendParams(
                                     oldSuspendDialogInfo,
-                                    suspendedAppExtras,
-                                    suspendedLauncherExtras);
+                                    oldSuspendedAppExtras,
+                                    oldSuspendedLauncherExtras,
+                                    false /* quarantined */);
                             suspendParamsMap = new ArrayMap<>();
                             suspendParamsMap.put(oldSuspendingPackage, suspendParams);
                         }
@@ -1989,13 +1991,12 @@
                             setBlockUninstallLPw(userId, name, true);
                         }
                         ps.setUserState(userId, ceDataInode, enabled, installed, stopped,
-                                notLaunched,
-                                hidden, distractionFlags, suspendParamsMap, instantApp,
-                                virtualPreload,
-                                enabledCaller, enabledComponents, disabledComponents, installReason,
-                                uninstallReason, harmfulAppWarning, splashScreenTheme,
-                                firstInstallTime != 0 ? firstInstallTime :
-                                        origFirstInstallTimes.getOrDefault(name, 0L),
+                                notLaunched, hidden, distractionFlags, suspendParamsMap, instantApp,
+                                virtualPreload, enabledCaller, enabledComponents,
+                                disabledComponents, installReason, uninstallReason,
+                                harmfulAppWarning, splashScreenTheme,
+                                firstInstallTime != 0 ? firstInstallTime
+                                        : origFirstInstallTimes.getOrDefault(name, 0L),
                                 minAspectRatio, archiveState);
 
                         mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
@@ -4824,6 +4825,7 @@
                 pw.print(userState.isNotLaunched() ? "l" : "L");
                 pw.print(userState.isInstantApp() ? "IA" : "ia");
                 pw.print(userState.isVirtualPreload() ? "VPI" : "vpi");
+                pw.print(userState.isQuarantined() ? "Q" : "q");
                 String harmfulAppWarning = userState.getHarmfulAppWarning();
                 pw.print(harmfulAppWarning != null ? "HA" : "ha");
                 pw.print(",");
@@ -5185,6 +5187,8 @@
             pw.print(userState.isInstantApp());
             pw.print(" virtual=");
             pw.println(userState.isVirtualPreload());
+            pw.print(" quarantined=");
+            pw.print(userState.isQuarantined());
             pw.print("      installReason=");
             pw.println(userState.getInstallReason());
 
@@ -5207,6 +5211,8 @@
                     if (params != null) {
                         pw.print(" dialogInfo=");
                         pw.print(params.getDialogInfo());
+                        pw.print(" quarantined=");
+                        pw.println(params.isQuarantined());
                     }
                     pw.println();
                 }
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 94e09f1..ddb045d 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -115,17 +115,18 @@
             boolean suspended, @Nullable PersistableBundle appExtras,
             @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
             @NonNull String callingPackage, @UserIdInt int userId, int callingUid,
-            boolean forQuietMode) {
+            boolean forQuietMode, boolean quarantined) {
         if (ArrayUtils.isEmpty(packageNames)) {
             return packageNames;
         }
-        if (suspended && !forQuietMode && !isSuspendAllowedForUser(snapshot, userId, callingUid)) {
+        if (suspended && !quarantined && !forQuietMode && !isSuspendAllowedForUser(snapshot, userId,
+                callingUid)) {
             Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
             return packageNames;
         }
 
         final SuspendParams newSuspendParams =
-                new SuspendParams(dialogInfo, appExtras, launcherExtras);
+                new SuspendParams(dialogInfo, appExtras, launcherExtras, quarantined);
 
         final List<String> unmodifiablePackages = new ArrayList<>(packageNames.length);
 
@@ -160,7 +161,6 @@
 
             final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
                     packageState.getUserStateOrDefault(userId).getSuspendParams();
-
             SuspendParams oldSuspendParams = suspendParamsMap == null
                     ? null : suspendParamsMap.get(packageName);
             boolean changed = !Objects.equals(oldSuspendParams, newSuspendParams);
@@ -213,14 +213,15 @@
             sendPackagesSuspendedForUser(
                     suspended ? Intent.ACTION_PACKAGES_SUSPENDED
                             : Intent.ACTION_PACKAGES_UNSUSPENDED,
-                    changedPackages, notifyUids.toArray(), userId);
+                    changedPackages, notifyUids.toArray(), quarantined, userId);
             sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId);
             mPm.scheduleWritePackageRestrictions(userId);
         }
         // Send the suspension changed broadcast to ensure suspension state is not stale.
         if (!changedPackagesList.isEmpty()) {
             sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
-                    changedPackagesList.toArray(new String[0]), changedUids.toArray(), userId);
+                    changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined,
+                    userId);
         }
         return unmodifiablePackages.toArray(new String[0]);
     }
@@ -354,7 +355,7 @@
                     new String[unsuspendedPackages.size()]);
             sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
             sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
-                    packageArray, unsuspendedUids.toArray(), userId);
+                    packageArray, unsuspendedUids.toArray(), false, userId);
         }
     }
 
@@ -618,11 +619,14 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     void sendPackagesSuspendedForUser(@NonNull String intent, @NonNull String[] pkgList,
-            @NonNull int[] uidList, int userId) {
+            @NonNull int[] uidList, boolean quarantined, int userId) {
         final Handler handler = mInjector.getHandler();
         final Bundle extras = new Bundle(3);
         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+        if (quarantined) {
+            extras.putBoolean(Intent.EXTRA_QUARANTINED, true);
+        }
         final int flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND;
         final Bundle options = new BroadcastOptions()
                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
@@ -672,7 +676,7 @@
                             snapshot, toSuspend.toArray(new String[0]), suspend,
                             null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
                             PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
-                            false /* forQuietMode */)));
+                            false /* forQuietMode */, false /* quarantined */)));
         }
         return unsuspendable.toArray(String[]::new);
     }
@@ -716,7 +720,7 @@
         setPackagesSuspended(snapshot, toSuspend.toArray(new String[0]),
                 suspend, null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
                 PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
-                true /* forQuietMode */);
+                true /* forQuietMode */, false /* quarantined */);
     }
 
     private Set<String> packagesToSuspendInQuietMode(Computer snapshot, int userId) {
diff --git a/services/core/java/com/android/server/pm/flags.aconfig b/services/core/java/com/android/server/pm/flags.aconfig
new file mode 100644
index 0000000..368a843
--- /dev/null
+++ b/services/core/java/com/android/server/pm/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.pm"
+
+flag {
+    name: "quarantined_enabled"
+    namespace: "package_manager_service"
+    description: "Feature flag for Quarantined state"
+    bug: "269127435"
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 94e9599..27812df 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -379,7 +379,10 @@
                 | flag(state.isVirtualPreload(), ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
                 | flag(state.isHidden(), ApplicationInfo.PRIVATE_FLAG_HIDDEN);
 
-        if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+        if ((flags & PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS) != 0
+                && state.isQuarantined()) {
+            ai.enabled = false;
+        } else  if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
         } else if (state.getEnabledState()
                 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 81915b4..7bc518c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -209,6 +209,13 @@
     boolean isVirtualPreload();
 
     /**
+     * @return whether the package is quarantined in order to minimize ad-spam and pop ups
+     * when-not-in-use.
+     * @hide
+     */
+    boolean isQuarantined();
+
+    /**
      * The "package:type/entry" form of the theme resource ID previously set as the splash screen.
      *
      * @hide
@@ -225,6 +232,7 @@
      */
     @PackageManager.UserMinAspectRatio
     int getMinAspectRatio();
+
     /**
      * Information about the archived state of an app. Set only if an app is archived.
      *
@@ -233,4 +241,5 @@
     @Immutable.Ignore
     @Nullable
     ArchiveState getArchiveState();
+
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index cce18a8..3534d75 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -129,6 +129,11 @@
         return false;
     }
 
+    @Override
+    public boolean isQuarantined() {
+        return false;
+    }
+
     @Nullable
     @Override
     public String getSplashScreenTheme() {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index d8c8af6..2349fbf 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -670,6 +670,21 @@
         return getBoolean(Booleans.VIRTUAL_PRELOADED);
     }
 
+    @Override
+    public boolean isQuarantined() {
+        if (!isSuspended()) {
+            return false;
+        }
+        final var suspendParams = mSuspendParams;
+        for (int i = 0, size = suspendParams.size(); i < size; i++) {
+            final SuspendParams params = suspendParams.valueAt(i);
+            if (params.isQuarantined()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 
 
 
@@ -879,7 +894,7 @@
     }
 
     @DataClass.Generated(
-            time = 1691186062924L,
+            time = 1691601685901L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
             inputSignatures = "private  int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate  long mCeDataInode\nprivate  int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate  void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate  boolean watchableEquals(com.android.server.utils.Watchable)\nprivate  int watchableHashCode()\nprivate  boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate  int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final  int INSTALLED\nprivate static final  int STOPPED\nprivate static final  int NOT_LAUNCHED\nprivate static final  int HIDDEN\nprivate static final  int INSTANT_APP\nprivate static final  int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index 15e3d0c..e342453 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm.pkg;
 
+import static android.content.pm.PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 
@@ -122,6 +123,10 @@
             return true;
         }
 
+        if ((flags & FILTER_OUT_QUARANTINED_COMPONENTS) != 0 && state.isQuarantined()) {
+            return false;
+        }
+
         // First check if the overall package is disabled; if the package is
         // enabled then fall through to check specific component
         switch (state.getEnabledState()) {
diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
index dc48a33..153238fa 100644
--- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java
+++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
@@ -42,16 +42,25 @@
     private static final String TAG_DIALOG_INFO = "dialog-info";
     private static final String TAG_APP_EXTRAS = "app-extras";
     private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
+    private static final String ATTR_QUARANTINED = "quarantined";
 
-    private final SuspendDialogInfo dialogInfo;
-    private final PersistableBundle appExtras;
-    private final PersistableBundle launcherExtras;
+    private final SuspendDialogInfo mDialogInfo;
+    private final PersistableBundle mAppExtras;
+    private final PersistableBundle mLauncherExtras;
+
+    private final boolean mQuarantined;
 
     public SuspendParams(SuspendDialogInfo dialogInfo, PersistableBundle appExtras,
             PersistableBundle launcherExtras) {
-        this.dialogInfo = dialogInfo;
-        this.appExtras = appExtras;
-        this.launcherExtras = launcherExtras;
+        this(dialogInfo, appExtras, launcherExtras, false /* quarantined */);
+    }
+
+    public SuspendParams(SuspendDialogInfo dialogInfo, PersistableBundle appExtras,
+            PersistableBundle launcherExtras, boolean quarantined) {
+        this.mDialogInfo = dialogInfo;
+        this.mAppExtras = appExtras;
+        this.mLauncherExtras = launcherExtras;
+        this.mQuarantined = quarantined;
     }
 
     @Override
@@ -63,13 +72,16 @@
             return false;
         }
         final SuspendParams other = (SuspendParams) obj;
-        if (!Objects.equals(dialogInfo, other.dialogInfo)) {
+        if (!Objects.equals(mDialogInfo, other.mDialogInfo)) {
             return false;
         }
-        if (!BaseBundle.kindofEquals(appExtras, other.appExtras)) {
+        if (!BaseBundle.kindofEquals(mAppExtras, other.mAppExtras)) {
             return false;
         }
-        if (!BaseBundle.kindofEquals(launcherExtras, other.launcherExtras)) {
+        if (!BaseBundle.kindofEquals(mLauncherExtras, other.mLauncherExtras)) {
+            return false;
+        }
+        if (mQuarantined != other.mQuarantined) {
             return false;
         }
         return true;
@@ -77,9 +89,10 @@
 
     @Override
     public int hashCode() {
-        int hashCode = Objects.hashCode(dialogInfo);
-        hashCode = 31 * hashCode + ((appExtras != null) ? appExtras.size() : 0);
-        hashCode = 31 * hashCode + ((launcherExtras != null) ? launcherExtras.size() : 0);
+        int hashCode = Objects.hashCode(mDialogInfo);
+        hashCode = 31 * hashCode + ((mAppExtras != null) ? mAppExtras.size() : 0);
+        hashCode = 31 * hashCode + ((mLauncherExtras != null) ? mLauncherExtras.size() : 0);
+        hashCode = 31 * hashCode + Boolean.hashCode(mQuarantined);
         return hashCode;
     }
 
@@ -89,25 +102,26 @@
      * @param out the {@link XmlSerializer} object
      */
     public void saveToXml(TypedXmlSerializer out) throws IOException {
-        if (dialogInfo != null) {
+        out.attributeBoolean(null, ATTR_QUARANTINED, mQuarantined);
+        if (mDialogInfo != null) {
             out.startTag(null, TAG_DIALOG_INFO);
-            dialogInfo.saveToXml(out);
+            mDialogInfo.saveToXml(out);
             out.endTag(null, TAG_DIALOG_INFO);
         }
-        if (appExtras != null) {
+        if (mAppExtras != null) {
             out.startTag(null, TAG_APP_EXTRAS);
             try {
-                appExtras.saveToXml(out);
+                mAppExtras.saveToXml(out);
             } catch (XmlPullParserException e) {
                 Slog.e(LOG_TAG, "Exception while trying to write appExtras."
                         + " Will be lost on reboot", e);
             }
             out.endTag(null, TAG_APP_EXTRAS);
         }
-        if (launcherExtras != null) {
+        if (mLauncherExtras != null) {
             out.startTag(null, TAG_LAUNCHER_EXTRAS);
             try {
-                launcherExtras.saveToXml(out);
+                mLauncherExtras.saveToXml(out);
             } catch (XmlPullParserException e) {
                 Slog.e(LOG_TAG, "Exception while trying to write launcherExtras."
                         + " Will be lost on reboot", e);
@@ -127,6 +141,8 @@
         PersistableBundle readAppExtras = null;
         PersistableBundle readLauncherExtras = null;
 
+        final boolean quarantined = in.getAttributeBoolean(null, ATTR_QUARANTINED, false);
+
         final int currentDepth = in.getDepth();
         int type;
         try {
@@ -157,18 +173,22 @@
             Slog.e(LOG_TAG, "Exception while trying to parse SuspendParams,"
                     + " some fields may default", e);
         }
-        return new SuspendParams(readDialogInfo, readAppExtras, readLauncherExtras);
+        return new SuspendParams(readDialogInfo, readAppExtras, readLauncherExtras, quarantined);
     }
 
     public SuspendDialogInfo getDialogInfo() {
-        return dialogInfo;
+        return mDialogInfo;
     }
 
     public PersistableBundle getAppExtras() {
-        return appExtras;
+        return mAppExtras;
     }
 
     public PersistableBundle getLauncherExtras() {
-        return launcherExtras;
+        return mLauncherExtras;
+    }
+
+    public boolean isQuarantined() {
+        return mQuarantined;
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d8cc8d3..57b6e37 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1329,7 +1329,7 @@
                     .notifyBeforePackageUnstopped(next.packageName);
             mAtmService.getPackageManagerInternalLocked().notifyComponentUsed(
                     next.packageName, next.mUserId,
-                    next.packageName); /* TODO: Verify if correct userid */
+                    next.packageName, next.toString()); /* TODO: Verify if correct userid */
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
                     + next.packageName + ": " + e);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b3fa782..af1bac8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11004,25 +11004,18 @@
         }
     }
 
-    private void dumpPerUserData(IndentingPrintWriter pw) {
+    private void dumpPersonalAppInfoForSystemUserNoLock(IndentingPrintWriter pw) {
+        wtfIfInLock();
+        PersonalAppsSuspensionHelper.forUser(mContext, UserHandle.USER_SYSTEM).dump(pw);
+    }
+
+    private void dumpPerUserPolicyData(IndentingPrintWriter pw) {
         int userCount = mUserData.size();
         for (int i = 0; i < userCount; i++) {
             int userId = mUserData.keyAt(i);
             DevicePolicyData policy = getUserData(userId);
             policy.dump(pw);
             pw.println();
-
-            if (userId == UserHandle.USER_SYSTEM) {
-                pw.increaseIndent();
-                PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
-                pw.decreaseIndent();
-                pw.println();
-            } else {
-                // pm.getUnsuspendablePackages() will fail if it's called for a different user;
-                // as this dump is mostly useful for system user anyways, we can just ignore the
-                // others (rather than changing the permission check in the PM method)
-                Slogf.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId);
-            }
         }
     }
 
@@ -11040,7 +11033,7 @@
                 pw.println();
                 mDeviceAdminServiceController.dump(pw);
                 pw.println();
-                dumpPerUserData(pw);
+                dumpPerUserPolicyData(pw);
                 pw.println();
                 mConstants.dump(pw);
                 pw.println();
@@ -11067,6 +11060,7 @@
                 mStateCache.dump(pw);
                 pw.println();
             }
+            dumpPersonalAppInfoForSystemUserNoLock(pw);
 
             synchronized (mSubscriptionsChangedListenerLock) {
                 pw.println("Subscription changed listener : " + mSubscriptionsChangedListener);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index 5cca5fa..6797576 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -40,7 +40,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 targetPackages, true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
 
         verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
@@ -64,14 +64,14 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 null /* packageNames */, true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
 
         assertThat(failedNames).isNull()
 
         failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOfNulls(0), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
 
         assertThat(failedNames).isEmpty()
     }
@@ -81,7 +81,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
-                Binder.getCallingUid(), false /* forQuietMode */)
+                Binder.getCallingUid(), false /* forQuietMode */, false /* quarantined */)
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(TEST_PACKAGE_2)
@@ -92,7 +92,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(DEVICE_OWNER_PACKAGE)
@@ -103,7 +103,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(NONEXISTENT_PACKAGE)
@@ -116,7 +116,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 knownPackages, true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)!!
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)!!
 
         assertThat(failedNames.size).isEqualTo(knownPackages.size)
         for (pkg in knownPackages) {
@@ -132,7 +132,7 @@
         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 knownPackages, true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, true /* forQuietMode */)!!
+                TEST_USER_ID, deviceOwnerUid, true /* forQuietMode */, false /* quarantined */)!!
 
         assertThat(failedNames.size).isEqualTo(1)
         assertThat(failedNames[0]).isEqualTo(MGMT_ROLE_HOLDER_PACKAGE)
@@ -144,13 +144,13 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 targetPackages, true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
         failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 targetPackages, false /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
 
         verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
@@ -202,7 +202,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
-                false /* forQuietMode */)
+                false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -220,7 +220,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
-                false /* forQuietMode */)
+                false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
@@ -265,7 +265,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
-                false /* forQuietMode */)
+                false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -280,7 +280,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
-                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
+                TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -295,7 +295,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
-                false /* forQuietMode */)
+                false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -310,7 +310,7 @@
         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
                 arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
                 null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
-                deviceOwnerUid, false /* forQuietMode */)
+                deviceOwnerUid, false /* forQuietMode */, false /* quarantined */)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -324,7 +324,7 @@
     @Throws(Exception::class)
     fun sendPackagesSuspendedForUser() {
         suspendPackageHelper.sendPackagesSuspendedForUser(
-            Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
+            Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, false, TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
                 anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable(),
@@ -341,7 +341,7 @@
     @Throws(Exception::class)
     fun sendPackagesSuspendModifiedForUser() {
         suspendPackageHelper.sendPackagesSuspendedForUser(
-            Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToChange, uidsToChange, TEST_USER_ID)
+            Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToChange, uidsToChange, false, TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper).sendPackageBroadcast(
                 eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index b539a76..943a9c47 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -236,7 +236,7 @@
         verify(getServices().packageManagerInternal, never())
                 .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
         verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
-                any(), anyBoolean(), any(), any(), any(), any(), anyInt());
+                any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt());
 
         final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
         poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7478778..f408ef0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -7527,7 +7527,7 @@
                 .cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
         // Verify that the apps are NOT unsuspeded.
         verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
-                any(), eq(false), any(), any(), any(), any(), anyInt());
+                any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt());
         // Verify that DPC is invoked to check policy compliance.
         verify(mContext.spiedContext).startActivityAsUser(
                 MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 24029b1..fc27edc 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -35,6 +35,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -68,6 +69,27 @@
         mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager();
     }
 
+    @After
+    public void tearDown() throws Exception {
+        // Changes to RoleManager persist between tests, so we need to clear out any funny
+        // business we did in previous tests.
+        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+        CallbackFuture future = new CallbackFuture();
+        runWithShellPermissionIdentity(
+                () -> {
+                    roleManager.setBypassingRoleQualification(false);
+                    roleManager.removeRoleHolderAsUser(
+                            "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+                            mContext.getPackageName(),
+                            /* flags= */ 0,
+                            Process.myUserHandle(),
+                            mContext.getMainExecutor(),
+                            future);
+                });
+
+        assertThat(future.get()).isEqualTo(true);
+    }
+
     @Test
     public void testBugreportFileManagerFileExists() {
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
@@ -131,14 +153,17 @@
                 new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
         RoleManager roleManager = mContext.getSystemService(RoleManager.class);
         CallbackFuture future = new CallbackFuture();
-        runWithShellPermissionIdentity(() -> roleManager.setBypassingRoleQualification(true));
-        runWithShellPermissionIdentity(() -> roleManager.addRoleHolderAsUser(
-                "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
-                mContext.getPackageName(),
-                /* flags= */ 0,
-                Process.myUserHandle(),
-                mContext.getMainExecutor(),
-                future));
+        runWithShellPermissionIdentity(
+                () -> {
+                    roleManager.setBypassingRoleQualification(true);
+                    roleManager.addRoleHolderAsUser(
+                            "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+                            mContext.getPackageName(),
+                            /* flags= */ 0,
+                            Process.myUserHandle(),
+                            mContext.getMainExecutor(),
+                            future);
+                });
 
         assertThat(future.get()).isEqualTo(true);
         mService.cancelBugreport(Binder.getCallingUid(), mContext.getPackageName());
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 64c2a4c..baacb57 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -85,11 +85,11 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -1328,10 +1328,24 @@
 
     private final Context mContext;
 
-    // Cache of Resource that has been created in getResourcesForSubId. Key is a Pair containing
-    // the Context and subId.
-    private static final Map<Pair<Context, Integer>, Resources> sResourcesCache =
-            new ConcurrentHashMap<>();
+    /**
+     * In order to prevent the overflow of the heap size due to an indiscriminate increase in the
+     * cache, the heap size of the resource cache is set sufficiently large.
+     */
+    private static final int MAX_RESOURCE_CACHE_ENTRY_COUNT = 10_000;
+
+    /**
+     * Cache of Resources that has been created in getResourcesForSubId. Key contains package name,
+     * and Configuration of Resources. If more than the maximum number of resources are stored in
+     * this cache, the least recently used Resources will be removed to maintain the maximum size.
+     */
+    private static final Map<Pair<String, Configuration>, Resources> sResourcesCache =
+            Collections.synchronizedMap(new LinkedHashMap<>(16, 0.75f, true) {
+                @Override
+                protected boolean removeEldestEntry(Entry eldest) {
+                    return size() > MAX_RESOURCE_CACHE_ENTRY_COUNT;
+                }
+            });
 
     /**
      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
@@ -2817,14 +2831,20 @@
     @NonNull
     public static Resources getResourcesForSubId(Context context, int subId,
             boolean useRootLocale) {
-        // Check if resources for this context and subId already exist in the resource cache.
-        // Resources that use the root locale are not cached.
-        Pair<Context, Integer> cacheKey = null;
-        if (isValidSubscriptionId(subId) && !useRootLocale) {
-            cacheKey = Pair.create(context, subId);
-            if (sResourcesCache.containsKey(cacheKey)) {
+        // Check if the Resources already exists in the cache based on the given context. Find a
+        // Resource that match Configuration.
+        Pair<String, Configuration> cacheKey = null;
+        if (isValidSubscriptionId(subId)) {
+            Configuration configurationKey =
+                    new Configuration(context.getResources().getConfiguration());
+            if (useRootLocale) {
+                configurationKey.setLocale(Locale.ROOT);
+            }
+            cacheKey = Pair.create(context.getPackageName(), configurationKey);
+            Resources cached = sResourcesCache.get(cacheKey);
+            if (cached != null) {
                 // Cache hit. Use cached Resources.
-                return sResourcesCache.get(cacheKey);
+                return cached;
             }
         }