Merge "Do not crash when duplication found in merged imsi list" am: 0d7ec6337e am: 350a4b3c85 am: 6b7cb8d231 am: 86b971c246

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2198759

Change-Id: I3ca43e74f824f495fc6e5d803db80d1c31966cd5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c73c5a0..e2c4cbd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -123,6 +123,7 @@
 import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -3158,7 +3159,8 @@
      * active merge set [A,B], we'd return a new template that primarily matches
      * A, but also matches B.
      */
-    private static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template,
+    @VisibleForTesting(visibility = PRIVATE)
+    static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template,
             @NonNull List<String[]> mergedList) {
         // Now there are several types of network which uses Subscriber Id to store network
         // information. For instance:
@@ -3168,6 +3170,12 @@
         if (template.getSubscriberIds().isEmpty()) return template;
 
         for (final String[] merged : mergedList) {
+            // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+            // duplicated items. Deduplication for better error handling.
+            final ArraySet mergedSet = new ArraySet(merged);
+            if (mergedSet.size() != merged.length) {
+                Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged));
+            }
             // TODO: Handle incompatible subscriberIds if that happens in practice.
             for (final String subscriberId : template.getSubscriberIds()) {
                 if (com.android.net.module.util.CollectionUtils.contains(merged, subscriberId)) {
@@ -3175,7 +3183,7 @@
                     // a template that matches all merged subscribers.
                     return new NetworkTemplate.Builder(template.getMatchRule())
                             .setWifiNetworkKeys(template.getWifiNetworkKeys())
-                            .setSubscriberIds(Set.of(merged))
+                            .setSubscriberIds(mergedSet)
                             .setMeteredness(template.getMeteredness())
                             .build();
                 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 0f2fe44..821ce5e 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -75,6 +75,7 @@
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
 import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
+import static com.android.server.net.NetworkPolicyManagerService.normalizeTemplate;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -2030,6 +2031,18 @@
                 METERED_NO, actualPolicy.template.getMeteredness());
     }
 
+    @Test
+    public void testNormalizeTemplate_duplicatedMergedImsiList() {
+        final NetworkTemplate template = new NetworkTemplate.Builder(MATCH_CARRIER)
+                .setSubscriberIds(Set.of(TEST_IMSI)).build();
+        final String[] mergedImsiGroup = new String[] {TEST_IMSI, TEST_IMSI};
+        final ArrayList<String[]> mergedList = new ArrayList<>();
+        mergedList.add(mergedImsiGroup);
+        // Verify the duplicated items in the merged IMSI list won't crash the system.
+        final NetworkTemplate result = normalizeTemplate(template, mergedList);
+        assertEquals(template, result);
+    }
+
     private String formatBlockedStateError(int uid, int rule, boolean metered,
             boolean backgroundRestricted) {
         return String.format(