Merge "Move myself to emeritus section"
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/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/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/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/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/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/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/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,