Snap for 10102166 from 2c8142d68ce434324953d2c1ccdd5d35f962ccf0 to mainline-tzdata4-release

Change-Id: Iaa8da582d9f3b0f2fda8651d93fd10adaf5ea88b
diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
index 3144229..1e184bb 100644
--- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
@@ -108,6 +108,10 @@
     private static final String SHA_1 = "SHA-1";
     private static final String SHA_256 = "SHA-256";
 
+    private static final int PACKAGE_NOT_PRIVILEGED = 0;
+    private static final int PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG = 1;
+    private static final int PACKAGE_PRIVILEGED_FROM_SIM = 2;
+
     // TODO(b/232273884): Turn feature on when find solution to handle the inter-carriers switching
     /**
      * Time delay to clear UICC rules after UICC is gone.
@@ -757,23 +761,35 @@
 
     @NonNull
     private PrivilegedPackageInfo getCurrentPrivilegedPackagesForAllUsers() {
+        Set<String> carrierServiceEligiblePackages = new ArraySet<>();
         Set<String> privilegedPackageNames = new ArraySet<>();
         Set<Integer> privilegedUids = new ArraySet<>();
         for (Map.Entry<String, Set<String>> e : mInstalledPackageCerts.entrySet()) {
-            if (isPackagePrivileged(e.getKey(), e.getValue())) {
-                privilegedPackageNames.add(e.getKey());
-                privilegedUids.addAll(getUidsForPackage(e.getKey(), /* invalidateCache= */ false));
+            final int priv = getPackagePrivilegedStatus(e.getKey(), e.getValue());
+            switch (priv) {
+                case PACKAGE_PRIVILEGED_FROM_SIM:
+                    carrierServiceEligiblePackages.add(e.getKey());
+                    // fallthrough
+                case PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG:
+                    privilegedPackageNames.add(e.getKey());
+                    privilegedUids.addAll(
+                            getUidsForPackage(e.getKey(), /* invalidateCache= */ false));
             }
         }
-        return new PrivilegedPackageInfo(privilegedPackageNames, privilegedUids,
-                getCarrierService(privilegedPackageNames));
+
+        return new PrivilegedPackageInfo(
+                privilegedPackageNames,
+                privilegedUids,
+                getCarrierService(carrierServiceEligiblePackages));
     }
 
     /**
-     * Returns true iff there is an overlap between the provided certificate hashes and the
-     * certificate hashes stored in mTestOverrideRules, mCarrierConfigRules and mUiccRules.
+     * Returns the privilege status of the provided package.
+     *
+     * <p>Returned privilege status depends on whether a package matches the certificates from
+     * carrier config, from test overrides or from certificates stored on the SIM.
      */
-    private boolean isPackagePrivileged(@NonNull String pkgName, @NonNull Set<String> certs) {
+    private int getPackagePrivilegedStatus(@NonNull String pkgName, @NonNull Set<String> certs) {
         // Double-nested for loops, but each collection should contain at most 2 elements in nearly
         // every case.
         // TODO(b/184382310) find a way to speed this up
@@ -782,23 +798,23 @@
             if (mTestOverrideRules != null) {
                 for (UiccAccessRule rule : mTestOverrideRules) {
                     if (rule.matches(cert, pkgName)) {
-                        return true;
+                        return PACKAGE_PRIVILEGED_FROM_SIM;
                     }
                 }
             } else {
-                for (UiccAccessRule rule : mCarrierConfigRules) {
-                    if (rule.matches(cert, pkgName)) {
-                        return true;
-                    }
-                }
                 for (UiccAccessRule rule : mUiccRules) {
                     if (rule.matches(cert, pkgName)) {
-                        return true;
+                        return PACKAGE_PRIVILEGED_FROM_SIM;
+                    }
+                }
+                for (UiccAccessRule rule : mCarrierConfigRules) {
+                    if (rule.matches(cert, pkgName)) {
+                        return PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG;
                     }
                 }
             }
         }
-        return false;
+        return PACKAGE_NOT_PRIVILEGED;
     }
 
     @NonNull
@@ -1067,13 +1083,13 @@
     }
 
     @NonNull
-    private Pair<String, Integer> getCarrierService(@NonNull Set<String> privilegedPackageNames) {
+    private Pair<String, Integer> getCarrierService(@NonNull Set<String> simPrivilegedPackages) {
         List<ResolveInfo> carrierServiceResolveInfos = mPackageManager.queryIntentServices(
                 new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), /* flags= */ 0);
         String carrierServicePackageName = null;
         for (ResolveInfo resolveInfo : carrierServiceResolveInfos) {
             String packageName = getPackageName(resolveInfo);
-            if (privilegedPackageNames.contains(packageName)) {
+            if (simPrivilegedPackages.contains(packageName)) {
                 carrierServicePackageName = packageName;
                 break;
             }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 891570b..5b8aca5 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -23,6 +23,7 @@
 import static com.android.internal.telephony.Phone.CS_FALLBACK;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.usage.NetworkStatsManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
@@ -925,8 +926,10 @@
      * {@code ImsReasonInfo#CODE_*} value.
      *
      * See {@link CarrierConfigManager#KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY}.
+     * This ImsReasonInfoKeyPair with this key stating will consider getExtraMessage a match
+     * if the carrier config messages starts with getExtraMessage result.
      */
-    private Map<Pair<Integer, String>, Integer> mImsReasonCodeMap = new ArrayMap<>();
+    private Map<ImsReasonInfoKeyPair, Integer> mImsReasonCodeMap = new ArrayMap<>();
 
 
     /**
@@ -985,6 +988,54 @@
     // Used for important operational related events for logging.
     private final LocalLog mOperationLocalLog = new LocalLog(64);
 
+    /**
+     * Container to ease passing around a tuple of two objects. This object provides a sensible
+     * implementation of equals(), returning true/false using equals() for one object (Integer)
+     * and startsWith() for another object (String). Also the startsWith() in this equals() method
+     * will return true for A.startsWith(B) if B.second starts with A.second.
+     */
+    private static class ImsReasonInfoKeyPair extends Pair<Integer, String> {
+
+        /**
+         * Constructor for a ImsReasonInfoKeyPair.
+         *
+         * @param first Integer in the ImsReasonInfoKeyPair
+         * @param second String in the ImsReasonInfoKeyPair
+         */
+        private ImsReasonInfoKeyPair(Integer first, String second) {
+            super(first, second);
+        }
+
+        /**
+         * Checks the two objects for equality by delegating to their respective
+         * {@link Object#equals(Object)} methods.
+         *
+         * @param o the {@link com.android.internal.telephony.imsphone.ImsReasonInfoKeyPair} to
+         *         which this one is to be checked for equality
+         * @return true if the underlying objects of the ImsReasonInfoKeyPair are
+         * considered equal and startsWith
+         */
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (!(o instanceof ImsReasonInfoKeyPair)) {
+                return false;
+            }
+            ImsReasonInfoKeyPair p = (ImsReasonInfoKeyPair) o;
+
+            return Objects.equals(p.first, first)
+                    && Objects.toString(second).startsWith(Objects.toString(p.second));
+        }
+
+        /**
+         * Compute a hash code using the hash code of the Integer key
+         *
+         * @return a hashcode of the first
+         */
+        @Override
+        public int hashCode() {
+            return (first == null ? 0 : first.hashCode());
+        }
+    }
     //***** Events
 
 
@@ -2824,7 +2875,7 @@
         if (message != null) {
             message = message.toLowerCase();
         }
-        mImsReasonCodeMap.put(new Pair<>(fromCode, message), toCode);
+        mImsReasonCodeMap.put(new ImsReasonInfoKeyPair(fromCode, message), toCode);
     }
 
     /**
@@ -2847,9 +2898,10 @@
         }
         log("maybeRemapReasonCode : fromCode = " + reasonInfo.getCode() + " ; message = "
                 + reason);
-        Pair<Integer, String> toCheck = new Pair<>(code, reason);
-        Pair<Integer, String> wildcardToCheck = new Pair<>(null, reason);
-        Pair<Integer, String> wildcardMessageToCheck = new Pair<>(code, null);
+        ImsReasonInfoKeyPair toCheck = new ImsReasonInfoKeyPair(code, reason);
+        ImsReasonInfoKeyPair wildcardToCheck = new ImsReasonInfoKeyPair(null, reason);
+        ImsReasonInfoKeyPair wildcardMessageToCheck = new ImsReasonInfoKeyPair(code, null);
+
         if (mImsReasonCodeMap.containsKey(toCheck)) {
             int toCode = mImsReasonCodeMap.get(toCheck);
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
index 221b2b5..07011a3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
@@ -889,7 +889,7 @@
     @Test
     public void testPackageDisabledAndThenEnabled() throws Exception {
         // Start with certs and packages installed
-        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
+        setupSimLoadedRules(ruleWithHashOnly(getHash(CERT_1)));
         setupInstalledPackages(
                 new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
                 new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2));
@@ -1032,9 +1032,12 @@
     }
 
     @Test
-    public void testGetCarrierService_haveCarrierServiceWithCarrierPrivileges() throws Exception {
-        // Only packages with CERT_1 have carrier privileges
-        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
+    public void testGetCarrierService_haveCarrierServiceWithSimCarrierPrivileges()
+            throws Exception {
+        // Package 1 has SIM loaded rules, making it eligible for carrier service bindings
+        setupSimLoadedRules(ruleWithHashOnly(getHash(CERT_1)));
+        // Package 2 has only carrier-config based rules, which is insufficient for carrier services
+        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_2)));
         // Setup all odd packages privileged, even packages not
         setupInstalledPackages(
                 new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
@@ -1061,7 +1064,6 @@
         assertEquals(PACKAGE_1, carrierServicePackageName);
         assertEquals(UID_1, carrierServiceUid);
 
-
         reset(mPackageManager);
         // Get CS again
         carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
@@ -1072,27 +1074,32 @@
         verify(mPackageManager, never()).queryIntentServices(any(), anyInt());
         assertEquals(PACKAGE_1, carrierServicePackageName);
         assertEquals(UID_1, carrierServiceUid);
-
     }
 
     @Test
-    public void testGetCarrierService_haveCarrierServiceWithNoCarrierPrivileges() throws Exception {
-        // Only packages with CERT_1 have carrier privileges
-        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
+    public void testGetCarrierService_haveCarrierServiceWithoutSimCarrierPrivileges()
+            throws Exception {
+        // Package 1 has no carrier privileges, package 2 has carrier-config based privileges, but
+        // no matching certificate on the SIM.
+        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_2)));
         // Setup all odd packages privileged, even packages not
         setupInstalledPackages(
                 new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
                 new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2),
                 new PackageCertInfo(PACKAGE_3, CERT_1, USER_1, UID_1));
-        // One declared CarrierService which has no carrier privileges
-        ResolveInfo noPrivilegeService = new ResolveInfoBuilder().setService(PACKAGE_2).build();
+        // Two declared CarrierService, only PACKAGE_1 has carrier privileges
+        ResolveInfo service1 = new ResolveInfoBuilder().setService(PACKAGE_1).build();
+        ResolveInfo service2 = new ResolveInfoBuilder().setService(PACKAGE_2).build();
         // Use doReturn instead of when/thenReturn which has NPE with unknown reason
-        doReturn(List.of(noPrivilegeService)).when(
-                mPackageManager).queryIntentServices(any(), anyInt());
+        doReturn(List.of(service1, service2))
+                .when(mPackageManager)
+                .queryIntentServices(any(), anyInt());
         when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1);
         when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2);
         when(mPackageManager.getPackageUid(eq(PACKAGE_3), anyInt())).thenReturn(UID_1);
 
+        // Verify that neither carrier service (no privileges, or carrier-config based privileges)
+        // are accepted.
         mCarrierPrivilegesTracker = createCarrierPrivilegesTracker();
         String carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
         int carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 1428b25..ec2209d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -1006,7 +1006,9 @@
         PersistableBundle bundle = new PersistableBundle();
         String[] mappings = new String[]{
                 "1014|call completed elsewhere|1014",
+                "1014|Call Rejected By User|510",
                 "1014|*|510",
+                "510|Call completed elsewhere|1014",
                 };
         bundle.putStringArray(CarrierConfigManager.KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY,
                 mappings);
@@ -1024,6 +1026,9 @@
                 new ImsReasonInfo(1014, 200, "Call Rejected By User"))); // 1014 -> 510
         assertEquals(ImsReasonInfo.CODE_ANSWERED_ELSEWHERE, mCTUT.maybeRemapReasonCode(
                 new ImsReasonInfo(1014, 200, "Call completed elsewhere"))); // 1014 -> 1014
+        assertEquals(ImsReasonInfo.CODE_ANSWERED_ELSEWHERE, mCTUT.maybeRemapReasonCode(
+                new ImsReasonInfo(510, 200,
+                        "Call completed elsewhere by instance urn:gsma:imei:xxx"))); // 510 -> 1014
 
         // Simulate that after SIM swap the new carrier config doesn't have the mapping for 1014
         loadReasonCodeRemapCarrierConfig();