Merge "Add missed break"
diff --git a/Android.bp b/Android.bp
index 02db27a..8b93dec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -211,6 +211,7 @@
         "apex_aidl_interface-java",
         "framework-protos",
         "updatable-driver-protos",
+        "ota_metadata_proto_java",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.0-java",
         "android.hardware.cas-V1.1-java",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index d3bef7f..5cbc78c 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -99,9 +99,7 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args +
-        // Needed for hidden libcore annotations for now.
-        " --ignore-classes-on-classpath ",
+    args: metalava_framework_docs_args,
     write_sdk_values: true,
 }
 
@@ -112,8 +110,6 @@
         "core/res/AndroidManifest.xml",
     ],
     args: metalava_framework_docs_args +
-        // Needed for hidden libcore annotations for now.
-        " --ignore-classes-on-classpath " +
         " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
     write_sdk_values: true,
 }
diff --git a/boot/Android.bp b/boot/Android.bp
index ef2abc8..3caede4 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -98,4 +98,12 @@
             dest: "hiddenapi-unsupported.csv",
         },
     ],
+
+    required: [
+        "platform-systemserverclasspath",
+    ],
+}
+
+platform_systemserverclasspath {
+    name: "platform-systemserverclasspath",
 }
diff --git a/boot/OWNERS b/boot/OWNERS
index 0648888..0e258d0 100644
--- a/boot/OWNERS
+++ b/boot/OWNERS
@@ -1,2 +1,6 @@
 # soong-team@ as the platform_bootclasspath module is tightly coupled with Soong
 file:platform/build/soong:/OWNERS
+
+# art-team@ manages the boot image profiles for frameworks
+per-file boot-* = calin@google.com, yawanng@google.com, ngeoffray@google.com
+per-file preloaded-classes* = calin@google.com, yawanng@google.com, ngeoffray@google.com
diff --git a/build/boot/boot-image-profile.txt b/build/boot/boot-image-profile.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/boot/boot-image-profile.txt
diff --git a/build/boot/preloaded-classes b/build/boot/preloaded-classes
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/boot/preloaded-classes
diff --git a/core/api/current.txt b/core/api/current.txt
index 7fd3bca..cd4e6f9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -31480,6 +31480,7 @@
     field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
     field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
     field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+    field @NonNull public static final android.print.PrintAttributes.MediaSize JPN_OE_PHOTO_L;
     field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
     field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
     field @NonNull public static final android.print.PrintAttributes.MediaSize NA_ARCH_A;
@@ -31501,7 +31502,6 @@
     field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
     field @NonNull public static final android.print.PrintAttributes.MediaSize NA_SUPER_B;
     field public static final android.print.PrintAttributes.MediaSize NA_TABLOID;
-    field @NonNull public static final android.print.PrintAttributes.MediaSize OE_PHOTO_L;
     field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
     field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
     field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 039c6b1..ea626b3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1124,10 +1124,11 @@
 package android.app.compat {
 
   public final class CompatChanges {
+    method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void addPackageOverrides(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
     method public static boolean isChangeEnabled(long);
     method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
-    method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
+    method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removePackageOverrides(@NonNull String, @NonNull java.util.Set<java.lang.Long>);
   }
 
   public final class PackageOverride {
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 8462cbe..6acbef2 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -3,9 +3,9 @@
 # Android Enterprise team
 rubinxu@google.com
 sandness@google.com
-eranm@google.com
 alexkershaw@google.com
 pgrafov@google.com
 
 # Emeritus
 yamasani@google.com
+eranm@google.com
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index 74e1ece..8ca43c4 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -26,9 +26,11 @@
 import android.os.UserHandle;
 
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IPlatformCompat;
 
 import java.util.Map;
+import java.util.Set;
 
 /**
  * CompatChanges APIs - to be used by platform code only (including mainline
@@ -98,15 +100,19 @@
     }
 
     /**
-     * Set an app compat override for a given package. This will check whether the caller is allowed
+     * Adds app compat overrides for a given package. This will check whether the caller is allowed
      * to perform this operation on the given apk and build. Only the installer package is allowed
      * to set overrides on a non-debuggable final build and a non-test apk.
      *
+     * <p>Note that calling this method doesn't remove previously added overrides for the given
+     * package if their change ID isn't in the given map, only replaces those that have the same
+     * change ID.
+     *
      * @param packageName The package name of the app in question.
-     * @param overrides A map from changeId to the override applied for this change id.
+     * @param overrides A map from change ID to the override applied for this change ID.
      */
     @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
-    public static void setPackageOverride(@NonNull String packageName,
+    public static void addPackageOverrides(@NonNull String packageName,
             @NonNull Map<Long, PackageOverride> overrides) {
         IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
@@ -117,4 +123,29 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Removes app compat overrides for a given package. This will check whether the caller is
+     * allowed to perform this operation on the given apk and build. Only the installer package is
+     * allowed to clear overrides on a non-debuggable final build and a non-test apk.
+     *
+     * <p>Note that calling this method with an empty set is a no-op and no overrides will be
+     * removed for the given package.
+     *
+     * @param packageName The package name of the app in question.
+     * @param overridesToRemove A set of change IDs for which to remove overrides.
+     */
+    @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+    public static void removePackageOverrides(@NonNull String packageName,
+            @NonNull Set<Long> overridesToRemove) {
+        IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+        CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig(
+                overridesToRemove);
+        try {
+            platformCompat.removeOverridesOnReleaseBuilds(config, packageName);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 9368b68..88bdb7f 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -23,6 +23,7 @@
 /** @hide */
 
 interface IRecoverySystem {
+    boolean allocateSpaceForUpdate(in String packageFilePath);
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 051447f..944b717 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -672,6 +672,14 @@
             if (!rs.setupBcb(command)) {
                 throw new IOException("Setup BCB failed");
             }
+            try {
+                if (!rs.allocateSpaceForUpdate(packageFile)) {
+                    throw new IOException("Failed to allocate space for update "
+                            + packageFile.getAbsolutePath());
+                }
+            } catch (RemoteException e) {
+                e.rethrowAsRuntimeException();
+            }
 
             // Having set up the BCB (bootloader control block), go ahead and reboot
             PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -1392,6 +1400,13 @@
     }
 
     /**
+     * Talks to RecoverySystemService via Binder to allocate space
+     */
+    private boolean allocateSpaceForUpdate(File packageFile) throws RemoteException {
+        return mService.allocateSpaceForUpdate(packageFile.getAbsolutePath());
+    }
+
+    /**
      * Talks to RecoverySystemService via Binder to clear up the BCB.
      */
     private boolean clearBcb() {
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index c198848..f508101 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -837,8 +837,8 @@
                 new MediaSize("JPN_YOU4", "android",
                         R.string.mediasize_japanese_you4, 4134, 9252);
         /** Japanese Photo L media size: 89mm x 127mm (3.5 x 5") */
-        public static final @NonNull MediaSize OE_PHOTO_L =
-                new MediaSize("OE_PHOTO_L", "android",
+        public static final @NonNull MediaSize JPN_OE_PHOTO_L =
+                new MediaSize("JPN_OE_PHOTO_L", "android",
                         R.string.mediasize_japanese_l, 3500, 5000);
 
         private final @NonNull String mId;
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 50f63f8..c75e238 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import libcore.internal.StringPool;
+import com.android.internal.util.StringPool;
 
 import java.io.Closeable;
 import java.io.EOFException;
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
index 36bc229..182dba7 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
@@ -39,14 +39,14 @@
      * Changes forced to be enabled.
      */
     public Set<Long> enabledChanges() {
-        return mChangeConfig.forceEnabledSet();
+        return mChangeConfig.getEnabledSet();
     }
 
     /**
      * Changes forced to be disabled.
      */
     public Set<Long> disabledChanges() {
-        return mChangeConfig.forceDisabledSet();
+        return mChangeConfig.getDisabledSet();
     }
 
     /**
@@ -84,8 +84,8 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        long[] enabled = mChangeConfig.forceEnabledChangesArray();
-        long[] disabled = mChangeConfig.forceDisabledChangesArray();
+        long[] enabled = mChangeConfig.getEnabledChangesArray();
+        long[] disabled = mChangeConfig.getDisabledChangesArray();
 
         dest.writeLongArray(enabled);
         dest.writeLongArray(disabled);
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl
new file mode 100644
index 0000000..441e553
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.compat;
+
+parcelable CompatibilityOverridesToRemoveConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
new file mode 100644
index 0000000..642f79c
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.compat;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Parcelable containing compat config change IDs for which to remove overrides for a given
+ * application.
+ * @hide
+ */
+public final class CompatibilityOverridesToRemoveConfig implements Parcelable {
+    public final Set<Long> changeIds;
+
+    public CompatibilityOverridesToRemoveConfig(Set<Long> changeIds) {
+        this.changeIds = changeIds;
+    }
+
+    private CompatibilityOverridesToRemoveConfig(Parcel in) {
+        int keyCount = in.readInt();
+        changeIds = new HashSet<>();
+        for (int i = 0; i < keyCount; i++) {
+            changeIds.add(in.readLong());
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(changeIds.size());
+        for (Long changeId : changeIds) {
+            dest.writeLong(changeId);
+        }
+    }
+
+    public static final Creator<CompatibilityOverridesToRemoveConfig> CREATOR =
+            new Creator<CompatibilityOverridesToRemoveConfig>() {
+
+                @Override
+                public CompatibilityOverridesToRemoveConfig createFromParcel(Parcel in) {
+                    return new CompatibilityOverridesToRemoveConfig(in);
+                }
+
+                @Override
+                public CompatibilityOverridesToRemoveConfig[] newArray(int size) {
+                    return new CompatibilityOverridesToRemoveConfig[size];
+                }
+            };
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 78d1d22..c9f1704 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,6 +22,7 @@
 
 parcelable CompatibilityChangeConfig;
 parcelable CompatibilityOverrideConfig;
+parcelable CompatibilityOverridesToRemoveConfig;
 parcelable CompatibilityChangeInfo;
 /**
  * Platform private API for talking with the PlatformCompat service.
@@ -204,6 +205,27 @@
     void clearOverrideForTest(long changeId, String packageName);
 
     /**
+     * Restores the default behaviour for compatibility changes on release builds.
+     *
+     * <p>The caller to this API needs to hold
+     * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+     * in {@code overridesToRemove} need to annotated with
+     * {@link android.compat.annotation.Overridable}.
+     *
+     * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+     * be {@code false}.
+     *
+     * <p>Note that this does not kill the app, and therefore overrides read from the app process
+     * will not be updated. Overrides read from the system process do take effect.
+     *
+     * @param overridesToRemove   parcelable containing the compat change overrides to be removed
+     * @param packageName         the package name of the app whose changes will be restored to the
+     *                            default behaviour
+     * @throws SecurityException if overriding changes is not permitted
+     */
+    void removeOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveConfig overridesToRemove, in String packageName);
+
+    /**
      * Enables all compatibility changes that have enabledSinceTargetSdk ==
      * {@param targetSdkVersion} for an app, subject to the policy.
      *
diff --git a/core/java/com/android/internal/util/StringPool.java b/core/java/com/android/internal/util/StringPool.java
new file mode 100644
index 0000000..c5180a3
--- /dev/null
+++ b/core/java/com/android/internal/util/StringPool.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * A pool of string instances. Unlike the {@link String#intern() VM's
+ * interned strings}, this pool provides no guarantee of reference equality.
+ * It is intended only to save allocations. This class is not thread safe.
+ *
+ * @hide
+ */
+public final class StringPool {
+
+    private final String[] mPool = new String[512];
+
+    /**
+     * Constructs string pool.
+     */
+    public StringPool() {
+    }
+
+    private static boolean contentEquals(String s, char[] chars, int start, int length) {
+        if (s.length() != length) {
+            return false;
+        }
+        for (int i = 0; i < length; i++) {
+            if (chars[start + i] != s.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns a string equal to {@code new String(array, start, length)}.
+     *
+     * @param array  buffer containing string chars
+     * @param start  offset in {@code array} where string starts
+     * @param length length of string
+     * @return string equal to {@code new String(array, start, length)}
+     */
+    public String get(char[] array, int start, int length) {
+        // Compute an arbitrary hash of the content
+        int hashCode = 0;
+        for (int i = start; i < start + length; i++) {
+            hashCode = (hashCode * 31) + array[i];
+        }
+
+        // Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap)
+        hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
+        hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4);
+        int index = hashCode & (mPool.length - 1);
+
+        String pooled = mPool[index];
+        if (pooled != null && contentEquals(pooled, array, start, length)) {
+            return pooled;
+        }
+
+        String result = new String(array, start, length);
+        mPool[index] = result;
+        return result;
+    }
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 855448b..114f395 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -630,6 +630,7 @@
     char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
     char saveResolvedClassesDelayMsOptsBuf[
             sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
+    char profileMinSavePeriodOptsBuf[sizeof("-Xps-min-save-period-ms:")-1 + PROPERTY_VALUE_MAX];
     char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
     char madviseWillNeedFileSizeVdex[
             sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];
@@ -662,6 +663,8 @@
     char extraOptsBuf[PROPERTY_VALUE_MAX];
     char voldDecryptBuf[PROPERTY_VALUE_MAX];
     char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
+    char perfettoJavaHeapStackOptBuf[
+            sizeof("-XX:PerfettoJavaHeapStackProf=") + PROPERTY_VALUE_MAX];
     enum {
       kEMDefault,
       kEMIntPortable,
@@ -776,6 +779,10 @@
     parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=",
                        "true");
 
+    // Enable PerfettoJavaHeapStackProf in the zygote
+    parseRuntimeOption("dalvik.vm.perfetto_javaheap", perfettoJavaHeapStackOptBuf,
+                       "-XX:PerfettoJavaHeapStackProf=", "true");
+
     if (primary_zygote) {
         addOption("-Xprimaryzygote");
     }
@@ -859,6 +866,9 @@
     parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf,
             "-Xps-save-resolved-classes-delay-ms:");
 
+    parseRuntimeOption("dalvik.vm.ps-min-save-period-ms", profileMinSavePeriodOptsBuf,
+            "-Xps-min-save-period-ms:");
+
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
       addOption("-XX:LowMemoryMode");
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index cbc08ba..6bdfe28 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -632,6 +632,13 @@
     <!-- The default minimal size of a PiP task, in both dimensions. -->
     <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
 
+    <!--
+      The overridable minimal size of a PiP task, in both dimensions.
+      Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
+      when the pinned stack size is overridden by app via minWidth/minHeight.
+    -->
+    <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
+
     <!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
     <dimen name="task_height_of_minimized_mode">80dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c06e7de..43f4300 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1941,6 +1941,7 @@
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
   <java-symbol type="dimen" name="default_minimal_size_resizable_task" />
   <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" />
+  <java-symbol type="dimen" name="overridable_minimal_size_pip_resizable_task" />
   <java-symbol type="dimen" name="task_height_of_minimized_mode" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
   <java-symbol type="bool" name="config_allowPriorityVibrationsInLowPowerMode" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index dd60dd4..1a63660 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -44,8 +44,6 @@
 import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
 import com.android.internal.util.AsyncChannel;
 
-import junit.framework.Assert;
-
 import java.io.IOException;
 import java.net.UnknownHostException;
 import java.util.List;
@@ -76,7 +74,11 @@
     private WifiManager mWifiManager;
     private Context mContext;
     // Verify connectivity state
-    private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
+    // ConnectivityManager.TYPE_* is deprecated and no longer extended, so use the max public
+    // network type - TYPE_VPN should be enough.
+    // TODO: Replace registering CONNECTIVITY_ACTION with registering NetworkCallback and check
+    //  network by NetworkCapabilities.TRANSPORT_* and NetworkCapabilities.hasTransport() instead.
+    private static final int NUM_NETWORK_TYPES = ConnectivityManager.TYPE_VPN + 1;
     private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
 
     public ConnectionUtil(Context context) {
diff --git a/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java
new file mode 100644
index 0000000..f67fd51
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public final class StringPoolTest extends AndroidTestCase {
+
+    public void testStringPool() {
+        StringPool stringPool = new StringPool();
+        String bcd = stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3);
+        assertEquals("bcd", bcd);
+        assertSame(bcd, stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3));
+    }
+
+    public void testHashCollision() {
+        StringPool stringPool = new StringPool();
+        char[] a = { (char) 1, (char) 0 };
+        char[] b = { (char) 0, (char) 31 };
+        assertEquals(new String(a).hashCode(), new String(b).hashCode());
+
+        String aString = stringPool.get(a, 0, 2);
+        assertEquals(new String(a), aString);
+        String bString = stringPool.get(b, 0, 2);
+        assertEquals(new String(b), bString);
+        assertSame(bString, stringPool.get(b, 0, 2));
+        assertNotSame(aString, stringPool.get(a, 0, 2));
+    }
+}
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index be865a0..3980d3a 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -293,6 +293,11 @@
         } catch (SecurityException e) {
             throw e;
         } catch (Exception e) {
+            // If a DeviceIdAttestationException was previously wrapped with some other type,
+            // let's throw the original exception instead of wrapping it yet again.
+            if (e.getCause() instanceof DeviceIdAttestationException) {
+                throw (DeviceIdAttestationException) e.getCause();
+            }
             throw new DeviceIdAttestationException("Unable to perform attestation", e);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 60bcf37..18c38c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -113,7 +113,8 @@
     }
 
     public DataUsageInfo getWifiDataUsageInfo() {
-        NetworkTemplate template = NetworkTemplate.buildTemplateWifiWildcard();
+        NetworkTemplate template = NetworkTemplate.buildTemplateWifi(
+                NetworkTemplate.WIFI_NETWORKID_ALL, null);
         return getDataUsageInfo(template);
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
index f7bee30..27d877d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
@@ -89,7 +89,8 @@
 
         mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll(SUB_ID);
         mNetworkTemplate2 = NetworkTemplate.buildTemplateMobileAll(SUB_ID_2);
-        mWifiNetworkTemplate = NetworkTemplate.buildTemplateWifiWildcard();
+        mWifiNetworkTemplate = NetworkTemplate.buildTemplateWifi(
+                NetworkTemplate.WIFI_NETWORKID_ALL, null);
     }
 
     @Test
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 54df53d..29d77a7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -45,6 +45,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Size;
 import android.view.SurfaceControl;
@@ -223,6 +224,7 @@
     private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
             mSurfaceControlTransactionFactory;
     private PictureInPictureParams mPictureInPictureParams;
+    private int mOverridableMinSize;
 
     /**
      * If set to {@code true}, the entering animation will be skipped and we will wait for
@@ -244,6 +246,8 @@
         mPipBoundsHandler = boundsHandler;
         mEnterExitAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipResizeAnimationDuration);
+        mOverridableMinSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task);
         mSurfaceTransactionHelper = surfaceTransactionHelper;
         mPipAnimationController = pipAnimationController;
         mPipUiEventLoggerLogger = pipUiEventLogger;
@@ -949,7 +953,14 @@
         // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout>
         // without minWidth/minHeight
         if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
-            return new Size(windowLayout.minWidth, windowLayout.minHeight);
+            // If either dimension is smaller than the allowed minimum, adjust them
+            // according to mOverridableMinSize and log to SafeNet
+            if (windowLayout.minWidth < mOverridableMinSize
+                    || windowLayout.minHeight < mOverridableMinSize) {
+                EventLog.writeEvent(0x534e4554, "174302616", -1, "");
+            }
+            return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize),
+                    Math.max(windowLayout.minHeight, mOverridableMinSize));
         }
         return null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index 42dde40..b8a468e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -252,7 +252,7 @@
                 dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
         if (intent != null) {
             final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                    mContext, 0, intent, 0, null, UserHandle.CURRENT);
+                    mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
             b.setContentIntent(pendingIntent);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 60ee75b..f6f8d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -193,7 +193,8 @@
         if (enabled) {
             mWaitingForTerminalState = true;
             if (DEBUG) Log.d(TAG, "Starting tethering");
-            mTetheringManager.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
+            mTetheringManager.startTethering(new TetheringRequest.Builder(
+                    TETHERING_WIFI).setShouldShowEntitlementUi(false).build(),
                     ConcurrentUtils.DIRECT_EXECUTOR,
                     new TetheringManager.StartTetheringCallback() {
                         @Override
diff --git a/services/Android.bp b/services/Android.bp
index 57a7bc5..1f4258d 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -156,13 +156,13 @@
     defaults: ["services-stubs-default"],
     check_api: {
         current: {
-            api_file: "api/non-updatable-current.txt",
-            removed_api_file: "api/non-updatable-removed.txt",
+            api_file: "api/current.txt",
+            removed_api_file: "api/removed.txt",
         },
         api_lint: {
             enabled: true,
             new_since: ":android-non-updatable.api.system-server.latest",
-            baseline_file: "api/non-updatable-lint-baseline.txt",
+            baseline_file: "api/lint-baseline.txt",
         },
     },
     dists: [
diff --git a/services/api/Android.bp b/services/api/Android.bp
index bbc8c72..ee7d49f 100644
--- a/services/api/Android.bp
+++ b/services/api/Android.bp
@@ -24,12 +24,12 @@
 
 filegroup {
     name: "non-updatable-system-server-current.txt",
-    srcs: ["non-updatable-current.txt"],
+    srcs: ["current.txt"],
     visibility: ["//frameworks/base/api"],
 }
 
 filegroup {
     name: "non-updatable-system-server-removed.txt",
-    srcs: ["non-updatable-removed.txt"],
+    srcs: ["removed.txt"],
     visibility: ["//frameworks/base/api"],
 }
diff --git a/services/api/current.txt b/services/api/current.txt
index 7c5c01e..6419b70 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -1,49 +1,4 @@
 // Signature format: 2.0
-package com.android.permission.persistence {
-
-  public interface RuntimePermissionsPersistence {
-    method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RuntimePermissionsState {
-    ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
-    method @Nullable public String getFingerprint();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
-    method public int getVersion();
-    field public static final int NO_VERSION = -1; // 0xffffffff
-  }
-
-  public static final class RuntimePermissionsState.PermissionState {
-    ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
-    method public int getFlags();
-    method @NonNull public String getName();
-    method public boolean isGranted();
-  }
-
-}
-
-package com.android.role.persistence {
-
-  public interface RolesPersistence {
-    method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RolesState {
-    ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
-    method @Nullable public String getPackagesHash();
-    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
-    method public int getVersion();
-  }
-
-}
-
 package com.android.server {
 
   public final class LocalManagerRegistry {
diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt
index e985ddb..b46d21e 100644
--- a/services/api/lint-baseline.txt
+++ b/services/api/lint-baseline.txt
@@ -1,4 +1,8 @@
 // Baseline format: 1.0
+NotCloseable: com.android.server.wifi.SupplicantManager:
+    Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager
+
+
 ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder):
     Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)}
 ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean):
diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt
deleted file mode 100644
index 6419b70..0000000
--- a/services/api/non-updatable-current.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-// Signature format: 2.0
-package com.android.server {
-
-  public final class LocalManagerRegistry {
-    method public static <T> void addManager(@NonNull Class<T>, @NonNull T);
-    method @Nullable public static <T> T getManager(@NonNull Class<T>);
-  }
-
-  public abstract class SystemService {
-    ctor public SystemService(@NonNull android.content.Context);
-    method @NonNull public final android.content.Context getContext();
-    method public boolean isUserSupported(@NonNull com.android.server.SystemService.TargetUser);
-    method public void onBootPhase(int);
-    method public abstract void onStart();
-    method public void onUserStarting(@NonNull com.android.server.SystemService.TargetUser);
-    method public void onUserStopped(@NonNull com.android.server.SystemService.TargetUser);
-    method public void onUserStopping(@NonNull com.android.server.SystemService.TargetUser);
-    method public void onUserSwitching(@Nullable com.android.server.SystemService.TargetUser, @NonNull com.android.server.SystemService.TargetUser);
-    method public void onUserUnlocked(@NonNull com.android.server.SystemService.TargetUser);
-    method public void onUserUnlocking(@NonNull com.android.server.SystemService.TargetUser);
-    method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder);
-    method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder, boolean);
-    field public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 0x226
-    field public static final int PHASE_BOOT_COMPLETED = 1000; // 0x3e8
-    field public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520; // 0x208
-    field public static final int PHASE_LOCK_SETTINGS_READY = 480; // 0x1e0
-    field public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 0x1f4
-    field public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 0x258
-    field public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 0x64
-  }
-
-  public static final class SystemService.TargetUser {
-    method @NonNull public android.os.UserHandle getUserHandle();
-  }
-
-}
-
-package com.android.server.stats {
-
-  public final class StatsHelper {
-    method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context);
-  }
-
-}
-
-package com.android.server.wifi {
-
-  public class SupplicantManager {
-    method public static void start();
-    method public static void stop();
-  }
-
-}
-
diff --git a/services/api/non-updatable-lint-baseline.txt b/services/api/non-updatable-lint-baseline.txt
deleted file mode 100644
index b46d21e..0000000
--- a/services/api/non-updatable-lint-baseline.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-// Baseline format: 1.0
-NotCloseable: com.android.server.wifi.SupplicantManager:
-    Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager
-
-
-ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder):
-    Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)}
-ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean):
-    Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)}
diff --git a/services/api/non-updatable-removed.txt b/services/api/non-updatable-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/api/non-updatable-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d9ecdda..8084de8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2873,6 +2873,8 @@
             // If we're enforcing fine starting in Q, we also want to enforce coarse even for
             // older SDK versions.
             locationQueryBuilder.setMinSdkVersionForCoarse(0);
+            locationQueryBuilder.setMinSdkVersionForCoarse(0);
+            locationQueryBuilder.setMinSdkVersionForEnforcement(0);
             shouldCheckLocationPermissions = true;
         }
 
@@ -3001,6 +3003,14 @@
         }
     }
 
+    private boolean checkFineLocationAccess(Record r) {
+        return checkFineLocationAccess(r, Build.VERSION_CODES.BASE);
+    }
+
+    private boolean checkCoarseLocationAccess(Record r) {
+        return checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE);
+    }
+
     /**
      * Note -- this method should only be used at the site of a permission check if you need to
      * explicitly allow apps below a certain SDK level access regardless of location permissions.
@@ -3016,6 +3026,8 @@
                         .setMethod("TelephonyRegistry push")
                         .setLogAsInfo(true) // we don't need to log an error every time we push
                         .setMinSdkVersionForFine(minSdk)
+                        .setMinSdkVersionForCoarse(minSdk)
+                        .setMinSdkVersionForEnforcement(minSdk)
                         .build();
 
         return Binder.withCleanCallingIdentity(() -> {
@@ -3040,6 +3052,8 @@
                         .setMethod("TelephonyRegistry push")
                         .setLogAsInfo(true) // we don't need to log an error every time we push
                         .setMinSdkVersionForCoarse(minSdk)
+                        .setMinSdkVersionForFine(Integer.MAX_VALUE)
+                        .setMinSdkVersionForEnforcement(minSdk)
                         .build();
 
         return Binder.withCleanCallingIdentity(() -> {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 45eb774..471d2af 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -87,6 +87,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -431,6 +432,7 @@
         public void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
             // Startup VCN instances
             synchronized (mLock) {
+                final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
                 mLastSnapshot = snapshot;
 
                 // Start any VCN instances as necessary
@@ -478,11 +480,29 @@
                         entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
                     }
                 }
+
+                final Map<ParcelUuid, Set<Integer>> oldSubGrpMappings =
+                        getSubGroupToSubIdMappings(oldSnapshot);
+                final Map<ParcelUuid, Set<Integer>> currSubGrpMappings =
+                        getSubGroupToSubIdMappings(mLastSnapshot);
+                if (!currSubGrpMappings.equals(oldSubGrpMappings)) {
+                    notifyAllPolicyListenersLocked();
+                }
             }
         }
     }
 
     @GuardedBy("mLock")
+    private Map<ParcelUuid, Set<Integer>> getSubGroupToSubIdMappings(
+            @NonNull TelephonySubscriptionSnapshot snapshot) {
+        final Map<ParcelUuid, Set<Integer>> subGrpMappings = new ArrayMap<>();
+        for (ParcelUuid subGrp : mVcns.keySet()) {
+            subGrpMappings.put(subGrp, snapshot.getAllSubIdsInGroup(subGrp));
+        }
+        return subGrpMappings;
+    }
+
+    @GuardedBy("mLock")
     private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) {
         final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown);
         if (vcnToTeardown == null) {
@@ -815,6 +835,8 @@
             if (isVcnManagedNetwork) {
                 ncBuilder.removeCapability(
                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+            } else {
+                ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
             }
 
             if (isRestrictedCarrierWifi) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 55e2696..9247568 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -33,6 +33,7 @@
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.OverrideAllowedState;
 import com.android.server.compat.config.Change;
@@ -370,6 +371,27 @@
         }
     }
 
+    /**
+     * Removes overrides whose change ID is specified in {@code overridesToRemove} that were
+     * previously added via {@link #addOverride(long, String, boolean)} or
+     * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package.
+     *
+     * <p>This restores the default behaviour for the given change IDs and app.
+     *
+     * @param overridesToRemove list of change IDs for which to restore the default behaviour.
+     * @param packageName       the package for which the overrides should be purged
+     */
+    void removePackageOverrides(CompatibilityOverridesToRemoveConfig overridesToRemove,
+            String packageName) {
+        synchronized (mChanges) {
+            for (Long changeId : overridesToRemove.changeIds) {
+                removeOverrideUnsafe(changeId, packageName);
+            }
+            saveOverrides();
+            invalidateCache();
+        }
+    }
+
     private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName,
             int targetSdkVersion) {
         LongArray allowed = new LongArray();
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 20469a2..2591f38 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -46,6 +46,7 @@
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.util.DumpUtils;
@@ -54,6 +55,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -187,7 +189,7 @@
             String packageName) {
         // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
         checkCompatChangeOverrideOverridablePermission();
-        checkAllCompatOverridesAreOverridable(overrides);
+        checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
         mCompatConfig.addOverrides(overrides, packageName);
     }
 
@@ -251,6 +253,16 @@
     }
 
     @Override
+    public void removeOverridesOnReleaseBuilds(
+            CompatibilityOverridesToRemoveConfig overridesToRemove,
+            String packageName) {
+        // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
+        checkCompatChangeOverrideOverridablePermission();
+        checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
+        mCompatConfig.removePackageOverrides(overridesToRemove, packageName);
+    }
+
+    @Override
     public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
         checkCompatChangeReadAndLogPermission();
         return mCompatConfig.getAppConfig(appInfo);
@@ -396,8 +408,8 @@
         }
     }
 
-    private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) {
-        for (Long changeId : overrides.overrides.keySet()) {
+    private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) {
+        for (Long changeId : changeIds) {
             if (!mCompatConfig.isOverridable(changeId)) {
                 throw new SecurityException("Only change ids marked as Overridable can be "
                         + "overridden.");
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index afaae8a..0677bd5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -806,7 +806,6 @@
                     Arrays.stream(device.getEncodings()).mapToObj(
                             AudioFormat::toLogFriendlyEncoding
                     ).collect(Collectors.joining(", ")));
-            // TODO(b/80297701) use the actual device type that system audio mode is connected to.
             if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) {
                 return device;
             }
@@ -1225,7 +1224,6 @@
         if (isSystemAudioActivated() && port < 0) {
             // If system audio mode is on and the new active source is not under the current device,
             // Will switch to ARC input.
-            // TODO(b/115637145): handle system aduio without ARC
             routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
         } else if (mIsSwitchDevice && port >= 0) {
             // If current device is a switch and the new active source is under it,
@@ -1326,7 +1324,6 @@
 
     // Handle the system audio(ARC) part of the logic on receiving routing change or information.
     private void handleRoutingChangeAndInformationForSystemAudio() {
-        // TODO(b/115637145): handle system aduio without ARC
         routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 3f949ba..ec41a2f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -475,7 +475,6 @@
      * @return newly created {@link HdmiCecMessage}
      */
     static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) {
-        // TODO(b/80297701) validate.
         return buildCommand(src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index 0907e5d..0864a44 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -142,8 +142,4 @@
                     }
                 });
     }
-
-    private void switchToRelevantInputForDeviceAt(int physicalAddress) {
-        // TODO(shubang): implement this method
-    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c01a115..29c3dd9 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6850,7 +6850,7 @@
                                     .appendPath(record.getKey()).build())
                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                             .putExtra(EXTRA_KEY, record.getKey()),
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     mSystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(),
                     pi);
@@ -7713,6 +7713,21 @@
             int rank, int count, boolean wasPosted, String listenerName) {
         final String canceledKey = r.getKey();
 
+        // Get pending intent used to create alarm, use FLAG_NO_CREATE if PendingIntent
+        // does not already exist, then null will be returned.
+        final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
+                REQUEST_CODE_TIMEOUT,
+                new Intent(ACTION_NOTIFICATION_TIMEOUT)
+                        .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
+                                .appendPath(r.getKey()).build())
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE);
+
+        // Cancel alarm corresponding to pi.
+        if (pi != null) {
+            mAlarmManager.cancel(pi);
+        }
+
         // Record caller.
         recordCallerLocked(r);
 
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 9a9e733..da472be 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -37,6 +37,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.util.XmlUtils;
+import com.android.server.pm.PackageManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -463,6 +464,7 @@
         return PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_REPOST,
                 new Intent(REPOST_ACTION)
+                        .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
                         .setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build())
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                         .putExtra(EXTRA_KEY, key)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 48fee0b..0d2cd62 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12528,6 +12528,7 @@
                     if (hasOldPkg) {
                         mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
                                 allPackageNames);
+                        mPermissionManager.revokeStoragePermissionsIfScopeExpanded(pkg, oldPkg);
                     }
                     if (hasPermissionDefinitionChanges) {
                         mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3ffca02..b500e16 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -206,6 +206,9 @@
     private static final int USER_PERMISSION_FLAGS = FLAG_PERMISSION_USER_SET
             | FLAG_PERMISSION_USER_FIXED;
 
+    /** All storage permissions */
+    private static final List<String> STORAGE_PERMISSIONS = new ArrayList<>();
+
     /** If the permission of the value is granted, so is the key */
     private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
 
@@ -214,6 +217,9 @@
                 Manifest.permission.ACCESS_FINE_LOCATION);
         FULLER_PERMISSION_MAP.put(Manifest.permission.INTERACT_ACROSS_USERS,
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+        STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+        STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
     }
 
     /** Lock to protect internal data access */
@@ -2266,6 +2272,49 @@
     }
 
     /**
+     * If the app is updated, and has scoped storage permissions, then it is possible that the
+     * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     */
+    private void revokeStoragePermissionsIfScopeExpanded(
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage,
+            @NonNull PermissionCallback permissionCallback) {
+        boolean downgradedSdk = oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+                && newPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q;
+        boolean upgradedSdk = oldPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q
+                && newPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q;
+        boolean newlyRequestsLegacy = !upgradedSdk && !oldPackage.isRequestLegacyExternalStorage()
+                && newPackage.isRequestLegacyExternalStorage();
+
+        if (!newlyRequestsLegacy && !downgradedSdk) {
+            return;
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(newPackage.getUid());
+        int numRequestedPermissions = newPackage.getRequestedPermissions().size();
+        for (int i = 0; i < numRequestedPermissions; i++) {
+            PermissionInfo permInfo = getPermissionInfo(newPackage.getRequestedPermissions().get(i),
+                    newPackage.getPackageName(), 0);
+            if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) {
+                continue;
+            }
+
+            EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(),
+                    "Revoking permission " + permInfo.name + " from package "
+                            + newPackage.getPackageName() + " as either the sdk downgraded "
+                            + downgradedSdk + " or newly requested legacy full storage "
+                            + newlyRequestsLegacy);
+
+            revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(),
+                    false, callingUid, userId, null, permissionCallback);
+        }
+
+    }
+
+    /**
      * We might auto-grant permissions if any permission of the group is already granted. Hence if
      * the group of a granted permission changes we need to revoke it to avoid having permissions of
      * the new group auto-granted.
@@ -4734,6 +4783,19 @@
                 @UserIdInt int userId) {
             return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId);
         }
+        /**
+         * If the app is updated, and has scoped storage permissions, then it is possible that the
+         * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+         * @param newPackage The new package that was installed
+         * @param oldPackage The old package that was updated
+         */
+        public void revokeStoragePermissionsIfScopeExpanded(
+                @NonNull AndroidPackage newPackage,
+                @NonNull AndroidPackage oldPackage
+        ) {
+            PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage,
+                    oldPackage, mDefaultPermissionCallback);
+        }
 
         @Override
         public void revokeRuntimePermissionsIfGroupChanged(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 393e852..a8e842f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -266,6 +266,17 @@
             @NonNull ArrayList<String> allPackageNames);
 
     /**
+     * If the app is updated, and has scoped storage permissions, then it is possible that the
+     * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     */
+    public abstract void revokeStoragePermissionsIfScopeExpanded(
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage
+    );
+
+    /**
      * Add all permissions in the given package.
      * <p>
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 24337f3..12e55e5 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -24,10 +24,13 @@
 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIED;
 import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode;
 import static android.os.UserHandle.USER_SYSTEM;
+import static android.ota.nano.OtaPackageMetadata.ApexMetadata;
 
 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
 
 import android.annotation.IntDef;
+import android.apex.CompressedApexInfo;
+import android.apex.CompressedApexInfoList;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
@@ -47,9 +50,11 @@
 import android.os.ShellCallback;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
+import android.sysprop.ApexProperties;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.FastImmutableArraySet;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -59,6 +64,7 @@
 import com.android.internal.widget.RebootEscrowListener;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.ApexManager;
 
 import libcore.io.IoUtils;
 
@@ -68,9 +74,13 @@
 import java.io.FileDescriptor;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 /**
  * The recovery system service is responsible for coordinating recovery related
@@ -871,6 +881,76 @@
         return rebootWithLskfImpl(packageName, reason, slotSwitch);
     }
 
+    public static boolean isUpdatableApexSupported() {
+        return ApexProperties.updatable().orElse(false);
+    }
+
+    // Metadata should be no more than few MB, if it's larger than 100MB something is wrong.
+    private static final long APEX_INFO_SIZE_LIMIT = 24 * 1024 * 100;
+
+    private static CompressedApexInfoList getCompressedApexInfoList(String packageFile)
+            throws IOException {
+        try (ZipFile zipFile = new ZipFile(packageFile)) {
+            final ZipEntry entry = zipFile.getEntry("apex_info.pb");
+            if (entry == null) {
+                return null;
+            }
+            if (entry.getSize() >= APEX_INFO_SIZE_LIMIT) {
+                throw new IllegalArgumentException("apex_info.pb has size "
+                        + entry.getSize()
+                        + " which is larger than the permitted limit" + APEX_INFO_SIZE_LIMIT);
+            }
+            if (entry.getSize() == 0) {
+                CompressedApexInfoList infoList = new CompressedApexInfoList();
+                infoList.apexInfos = new CompressedApexInfo[0];
+                return infoList;
+            }
+            Log.i(TAG, "Allocating " + entry.getSize()
+                    + " bytes of memory to store OTA Metadata");
+            byte[] data = new byte[(int) entry.getSize()];
+
+            try (InputStream is = zipFile.getInputStream(entry)) {
+                int bytesRead = is.read(data);
+                String msg = "Read " + bytesRead + " when expecting " + data.length;
+                Log.e(TAG, msg);
+                if (bytesRead != data.length) {
+                    throw new IOException(msg);
+                }
+            }
+            ApexMetadata metadata = ApexMetadata.parseFrom(data);
+            CompressedApexInfoList apexInfoList = new CompressedApexInfoList();
+            apexInfoList.apexInfos =
+                    Arrays.stream(metadata.apexInfo).filter(apex -> apex.isCompressed).map(apex -> {
+                        CompressedApexInfo info = new CompressedApexInfo();
+                        info.moduleName = apex.packageName;
+                        info.decompressedSize = apex.decompressedSize;
+                        info.versionCode = apex.version;
+                        return info;
+                    }).toArray(CompressedApexInfo[]::new);
+            return apexInfoList;
+        }
+    }
+
+    @Override
+    public boolean allocateSpaceForUpdate(String packageFile) {
+        if (!isUpdatableApexSupported()) {
+            Log.i(TAG, "Updatable Apex not supported, "
+                    + "allocateSpaceForUpdate does nothing.");
+            return true;
+        }
+        try {
+            CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile);
+            ApexManager apexManager = ApexManager.getInstance();
+            apexManager.reserveSpaceForCompressedApex(apexInfoList);
+            return true;
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        } catch (IOException | UnsupportedOperationException e) {
+            Slog.e(TAG, "Failed to reserve space for compressed apex: ", e);
+        }
+        return false;
+    }
+
     @Override // Binder call
     public boolean isLskfCaptured(String packageName) {
         enforcePermissionForResumeOnReboot();
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c4a42ab..281d2c9 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -512,7 +512,7 @@
             setStatusBarState(mLockTaskModeState, userId);
             setKeyguardState(mLockTaskModeState, userId);
             if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
-                lockKeyguardIfNeeded();
+                lockKeyguardIfNeeded(userId);
             }
             if (getDevicePolicyManager() != null) {
                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
@@ -824,15 +824,15 @@
      * Helper method for locking the device immediately. This may be necessary when the device
      * leaves the pinned mode.
      */
-    private void lockKeyguardIfNeeded() {
-        if (shouldLockKeyguard()) {
+    private void lockKeyguardIfNeeded(int userId) {
+        if (shouldLockKeyguard(userId)) {
             mWindowManager.lockNow(null);
             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
             getLockPatternUtils().requireCredentialEntry(USER_ALL);
         }
     }
 
-    private boolean shouldLockKeyguard() {
+    private boolean shouldLockKeyguard(int userId) {
         // This functionality should be kept consistent with
         // com.android.settings.security.ScreenPinningSettings (see b/127605586)
         try {
@@ -842,7 +842,7 @@
         } catch (Settings.SettingNotFoundException e) {
             // Log to SafetyNet for b/127605586
             android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
-            return getLockPatternUtils().isSecure(USER_CURRENT);
+            return getLockPatternUtils().isSecure(userId);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index 7bdc87e..6b9aa18 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -115,7 +115,12 @@
         return this;
     }
 
-    CompatConfigBuilder addOverridableChangeWithId(long id) {
+    CompatConfigBuilder addEnabledOverridableChangeWithId(long id) {
+        mChanges.add(new CompatChange(id, "", -1, -1, false, false, "", true));
+        return this;
+    }
+
+    CompatConfigBuilder addDisabledOverridableChangeWithId(long id) {
         mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true));
         return this;
     }
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index a866363..0248b9b 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.compat.AndroidBuildClassifier;
 import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,6 +51,10 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 
 @RunWith(AndroidJUnit4.class)
@@ -249,7 +254,7 @@
         when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
             .thenReturn(applicationInfo);
 
-        // Force the validator to prevent overriding the change by using a user build.
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
         when(mBuildClassifier.isFinalBuild()).thenReturn(true);
 
@@ -261,10 +266,12 @@
 
     @Test
     public void testInstallerCanSetOverrides() throws Exception {
-        final long changeId = 1234L;
-        final int installerUid = 23;
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        // We make disabledChangeId2 non-overridable to make sure it is ignored.
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
-                .addOverridableChangeWithId(1234L)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledChangeWithId(disabledChangeId2)
                 .build();
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("com.some.package")
@@ -274,19 +281,56 @@
         when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
                 .thenReturn(applicationInfo);
 
-        // Force the validator to prevent overriding the change by using a user build.
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
         when(mBuildClassifier.isFinalBuild()).thenReturn(true);
 
         CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
-                Collections.singletonMap(1234L,
+                Collections.singletonMap(disabledChangeId1,
                         new PackageOverride.Builder()
                                 .setMaxVersionCode(99L)
                                 .setEnabled(true)
                                 .build()));
 
         compatConfig.addOverrides(config, "com.some.package");
-        assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse();
+    }
+
+    @Test
+    public void testPreventInstallerSetNonOverridable() throws Exception {
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        final long disabledChangeId3 = 1236L;
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledChangeWithId(disabledChangeId2)
+                .addDisabledOverridableChangeWithId(disabledChangeId3)
+                .build();
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package")
+                .build();
+        PackageManager packageManager = mock(PackageManager.class);
+        when(mContext.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(applicationInfo);
+
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        Map<Long, PackageOverride> overrides = new HashMap<>();
+        overrides.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build());
+        overrides.put(disabledChangeId2, new PackageOverride.Builder().setEnabled(true).build());
+        overrides.put(disabledChangeId3, new PackageOverride.Builder().setEnabled(true).build());
+        CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides);
+
+        assertThrows(SecurityException.class,
+                () -> compatConfig.addOverrides(config, "com.some.package")
+        );
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isFalse();
     }
 
     @Test
@@ -459,7 +503,7 @@
         assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
 
         // Reject all override attempts.
-        // Force the validator to prevent overriding the change by using a user build.
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
         when(mBuildClassifier.isFinalBuild()).thenReturn(false);
         // Try to turn off change, but validator prevents it.
@@ -481,7 +525,7 @@
                 .thenReturn(applicationInfo);
 
         // Reject all override attempts.
-        // Force the validator to prevent overriding the change by using a user build.
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
         when(mBuildClassifier.isFinalBuild()).thenReturn(true);
         // Try to remove a non existing override, and it doesn't fail.
@@ -509,6 +553,90 @@
     }
 
     @Test
+    public void testInstallerCanRemoveOverrides() throws Exception {
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        final long enabledChangeId = 1236L;
+        // We make disabledChangeId2 non-overridable to make sure it is ignored.
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledChangeWithId(disabledChangeId2)
+                .addEnabledOverridableChangeWithId(enabledChangeId)
+                .build();
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package")
+                .build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(applicationInfo);
+
+        assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue();
+        assertThat(compatConfig.addOverride(enabledChangeId, "com.some.package", false)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isFalse();
+
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        Set<Long> overridesToRemove = new HashSet<>();
+        overridesToRemove.add(disabledChangeId1);
+        overridesToRemove.add(enabledChangeId);
+        CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig(
+                overridesToRemove);
+
+        compatConfig.removePackageOverrides(config, "com.some.package");
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isTrue();
+    }
+
+    @Test
+    public void testPreventInstallerRemoveNonOverridable() throws Exception {
+        final long disabledChangeId1 = 1234L;
+        final long disabledChangeId2 = 1235L;
+        final long disabledChangeId3 = 1236L;
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledOverridableChangeWithId(disabledChangeId1)
+                .addDisabledChangeWithId(disabledChangeId2)
+                .addDisabledOverridableChangeWithId(disabledChangeId3)
+                .build();
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package")
+                .build();
+        PackageManager packageManager = mock(PackageManager.class);
+        when(mContext.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(applicationInfo);
+
+        assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue();
+        assertThat(compatConfig.addOverride(disabledChangeId3, "com.some.package", true)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue();
+
+        // Force the validator to prevent overriding non-overridable changes by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        Set<Long> overridesToRemove = new HashSet<>();
+        overridesToRemove.add(disabledChangeId1);
+        overridesToRemove.add(disabledChangeId2);
+        overridesToRemove.add(disabledChangeId3);
+        CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig(
+                overridesToRemove);
+
+        assertThrows(SecurityException.class,
+                () -> compatConfig.removePackageOverrides(config, "com.some.package")
+        );
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue();
+    }
+
+    @Test
     public void testEnableTargetSdkChangesForPackage() throws Exception {
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addEnabledChangeWithId(1L)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index a2664e5..9accd49 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -98,7 +98,7 @@
                 .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
                 .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L)
                 .addLoggingOnlyChangeWithId(7L)
-                .addOverridableChangeWithId(8L)
+                .addDisabledOverridableChangeWithId(8L)
                 .build();
         mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
         assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 3deeea2..c2ead5f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -49,6 +49,7 @@
 
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
+import com.android.server.pm.PackageManagerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -257,6 +258,17 @@
     }
 
     @Test
+    public void testSnoozeSentToAndroid() throws Exception {
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r, 1000);
+        ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+        verify(mAm, times(1)).setExactAndAllowWhileIdle(
+                anyInt(), anyLong(), captor.capture());
+        assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME,
+                captor.getValue().getIntent().getPackage());
+    }
+
+    @Test
     public void testSnooze() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, (String) null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index e345bec..fdc01b4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -450,7 +450,7 @@
         Settings.Secure.clearProviderForTest();
 
         // AND a password is set
-        when(mLockPatternUtils.isSecure(anyInt()))
+        when(mLockPatternUtils.isSecure(TEST_USER_ID))
                 .thenReturn(true);
 
         // AND there is a task record
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 25b062f..502bfa3 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -86,8 +86,9 @@
             private String mCallingFeatureId;
             private int mCallingUid;
             private int mCallingPid;
-            private int mMinSdkVersionForCoarse = Integer.MAX_VALUE;
-            private int mMinSdkVersionForFine = Integer.MAX_VALUE;
+            private int mMinSdkVersionForCoarse = -1;
+            private int mMinSdkVersionForFine = -1;
+            private int mMinSdkVersionForEnforcement = -1;
             private boolean mLogAsInfo = false;
             private String mMethod;
 
@@ -125,7 +126,14 @@
 
             /**
              * Apps that target at least this sdk version will be checked for coarse location
-             * permission. Defaults to INT_MAX (which means don't check)
+             * permission. This method MUST be called before calling {@link #build()}. Otherwise, an
+             * {@link IllegalArgumentException} will be thrown.
+             *
+             * Additionally, if both the argument to this method and
+             * {@link #setMinSdkVersionForFine} are greater than {@link Build.VERSION_CODES#BASE},
+             * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to
+             * affirm that you do not want any location checks below a certain SDK version.
+             * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}.
              */
             public Builder setMinSdkVersionForCoarse(
                     int minSdkVersionForCoarse) {
@@ -135,7 +143,14 @@
 
             /**
              * Apps that target at least this sdk version will be checked for fine location
-             * permission. Defaults to INT_MAX (which means don't check)
+             * permission.  This method MUST be called before calling {@link #build()}.
+             * Otherwise, an {@link IllegalArgumentException} will be thrown.
+             *
+             * Additionally, if both the argument to this method and
+             * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE},
+             * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to
+             * affirm that you do not want any location checks below a certain SDK version.
+             * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}.
              */
             public Builder setMinSdkVersionForFine(
                     int minSdkVersionForFine) {
@@ -144,6 +159,17 @@
             }
 
             /**
+             * If both the argument to {@link #setMinSdkVersionForFine} and
+             * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE},
+             * this method must be called with the min of the two to
+             * affirm that you do not want any location checks below a certain SDK version.
+             */
+            public Builder setMinSdkVersionForEnforcement(int minSdkVersionForEnforcement) {
+                mMinSdkVersionForEnforcement = minSdkVersionForEnforcement;
+                return this;
+            }
+
+            /**
              * Optional, for logging purposes only.
              */
             public Builder setMethod(String method) {
@@ -161,6 +187,26 @@
 
             /** build LocationPermissionQuery */
             public LocationPermissionQuery build() {
+                if (mMinSdkVersionForCoarse < 0 || mMinSdkVersionForFine < 0) {
+                    throw new IllegalArgumentException("Must specify min sdk versions for"
+                            + " enforcement for both coarse and fine permissions");
+                }
+                if (mMinSdkVersionForFine > Build.VERSION_CODES.BASE
+                        && mMinSdkVersionForCoarse > Build.VERSION_CODES.BASE) {
+                    if (mMinSdkVersionForEnforcement != Math.min(
+                            mMinSdkVersionForCoarse, mMinSdkVersionForFine)) {
+                        throw new IllegalArgumentException("setMinSdkVersionForEnforcement must be"
+                                + " called.");
+                    }
+                }
+
+                if (mMinSdkVersionForFine < mMinSdkVersionForCoarse) {
+                    throw new IllegalArgumentException("Since fine location permission includes"
+                            + " access to coarse location, the min sdk level for enforcement of"
+                            + " the fine location permission must not be less than the min sdk"
+                            + " level for enforcement of the coarse location permission.");
+                }
+
                 return new LocationPermissionQuery(mCallingPackage, mCallingFeatureId,
                         mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine,
                         mLogAsInfo, mMethod);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index dd474f0..f6ba7be 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4106,6 +4106,26 @@
         public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY =
                 KEY_PREFIX + "rcs_feature_tag_allowed_string_array";
 
+        /**
+         * Flag indicating whether or not carrier forbids device send the RCS request when the
+         * device receive the network response with the SIP code 489 BAD EVENT.
+         * <p>
+         * The default value for this key is {@code false}.
+         * @hide
+         */
+        public static final String KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL =
+                KEY_PREFIX + "rcs_request_forbidden_by_sip_489_bool";
+
+        /**
+         * Indicates the interval that SUBSCRIBE requests from applications will be retried at when
+         * the carrier network has responded to a previous request with a forbidden error.
+         * <p>
+         * The default value for this key is 20 minutes.
+         * @hide
+         */
+        public static final String KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG =
+                KEY_PREFIX + "rcs_request_retry_interval_millis_long";
+
         private Ims() {}
 
         private static PersistableBundle getDefaults() {
@@ -4119,6 +4139,8 @@
             defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
             defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60);
+            defaults.putBoolean(KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, false);
+            defaults.putLong(KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG, 20 * 60 * 1000);
             defaults.putStringArray(KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, new String[]{
                     "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\"",
                     "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"",
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 97078c3..3c55b7c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2398,6 +2398,12 @@
     String getLastUcePidfXmlShell(int subId);
 
     /**
+      * Remove UCE requests cannot be sent to the network status.
+      * Note: This is designed for a SHELL command only.
+      */
+    boolean removeUceRequestDisallowedStatus(int subId);
+
+    /**
      * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
      * specified thresholds.
      */
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index aa4b5f8..9ecd82f 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -77,6 +77,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -98,6 +99,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.UUID;
 
@@ -326,6 +328,17 @@
             return subIdToGroupMap.get(invocation.getArgument(0));
         }).when(snapshot).getGroupForSubId(anyInt());
 
+        doAnswer(invocation -> {
+            final ParcelUuid subGrp = invocation.getArgument(0);
+            final Set<Integer> subIds = new ArraySet<>();
+            for (Entry<Integer, ParcelUuid> entry : subIdToGroupMap.entrySet()) {
+                if (entry.getValue().equals(subGrp)) {
+                    subIds.add(entry.getKey());
+                }
+            }
+            return subIds;
+        }).when(snapshot).getAllSubIdsInGroup(any());
+
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         cb.onNewSnapshot(snapshot);
 
@@ -914,6 +927,18 @@
         verify(mMockPolicyListener).onPolicyChanged();
     }
 
+    @Test
+    public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
+        startAndGetVcnInstance(TEST_UUID_2);
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                Collections.singleton(TEST_UUID_2),
+                Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
+
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
     private void triggerVcnSafeMode(
             @NonNull ParcelUuid subGroup,
             @NonNull TelephonySubscriptionSnapshot snapshot,