Merge "Fix crash when the FEATURE_TELEPHONY_EUICC is not defined" into main
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 8de8ae1..d7eb4b8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -8795,12 +8795,18 @@
     }
 
     /**
-     * Returns the service state information on specified subscription.
+     * Returns the service state information on specified SIM slot.
      */
     @Override
-    public ServiceState getServiceStateForSubscriber(int subId,
-            boolean renounceFineLocationAccess, boolean renounceCoarseLocationAccess,
-            String callingPackage, String callingFeatureId) {
+    public ServiceState getServiceStateForSlot(int slotIndex, boolean renounceFineLocationAccess,
+            boolean renounceCoarseLocationAccess, String callingPackage, String callingFeatureId) {
+        Phone phone = PhoneFactory.getPhone(slotIndex);
+        if (phone == null) {
+            loge("getServiceStateForSlot retuning null for invalid slotIndex=" + slotIndex);
+            return null;
+        }
+
+        int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mApp, subId, callingPackage, callingFeatureId, "getServiceStateForSubscriber")) {
             return null;
@@ -8819,7 +8825,7 @@
                                     .setCallingFeatureId(callingFeatureId)
                                     .setCallingPid(Binder.getCallingPid())
                                     .setCallingUid(Binder.getCallingUid())
-                                    .setMethod("getServiceStateForSubscriber")
+                                    .setMethod("getServiceStateForSlot")
                                     .setLogAsInfo(true)
                                     .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
                                     .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
@@ -8837,7 +8843,7 @@
                                     .setCallingFeatureId(callingFeatureId)
                                     .setCallingPid(Binder.getCallingPid())
                                     .setCallingUid(Binder.getCallingUid())
-                                    .setMethod("getServiceStateForSubscriber")
+                                    .setMethod("getServiceStateForSlot")
                                     .setLogAsInfo(true)
                                     .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
                                     .setMinSdkVersionForFine(Integer.MAX_VALUE)
@@ -8847,26 +8853,18 @@
                     coarseLocationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
         }
 
-        final Phone phone = getPhone(subId);
-        if (phone == null) {
-            return null;
-        }
-
         final long identity = Binder.clearCallingIdentity();
-
-        boolean isCallingPackageDataService = phone.getDataServicePackages()
-                .contains(callingPackage);
         try {
-            // isActiveSubId requires READ_PHONE_STATE, which we already check for above
             SubscriptionInfoInternal subInfo = getSubscriptionManagerService()
                     .getSubscriptionInfoInternal(subId);
-            if (subInfo == null || !subInfo.isActive()) {
-                Rlog.d(LOG_TAG, "getServiceStateForSubscriber returning null for inactive "
-                        + "subId=" + subId);
+            if (subInfo != null && !subInfo.isActive()) {
+                log("getServiceStateForSlot returning null for inactive subId=" + subId);
                 return null;
             }
 
             ServiceState ss = phone.getServiceState();
+            boolean isCallingPackageDataService = phone.getDataServicePackages()
+                    .contains(callingPackage);
 
             // Scrub out the location info in ServiceState depending on what level of access
             // the caller has.
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index ea72acd..4ac59e7 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -61,7 +61,9 @@
 import com.android.internal.telephony.TelephonyCountryDetector;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.satellite.SatelliteConfig;
+import com.android.internal.telephony.satellite.SatelliteConstants;
 import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.satellite.metrics.ConfigUpdaterMetricsStats;
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.phone.PhoneGlobals;
 
@@ -190,6 +192,7 @@
     private static final String CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY =
             "config_updater_satellite_is_allow_access_control";
     private SharedPreferences mSharedPreferences;
+    private final ConfigUpdaterMetricsStats mConfigUpdaterMetricsStats;
 
     /**
      * Map key: binder of the callback, value: callback to receive the satellite communication
@@ -241,6 +244,7 @@
                 handleIsSatelliteSupportedResult(resultCode, resultData);
             }
         };
+        mConfigUpdaterMetricsStats = ConfigUpdaterMetricsStats.getOrCreateInstance();
         // Init the SatelliteOnDeviceAccessController so that the S2 level can be cached
         initSatelliteOnDeviceAccessController();
     }
@@ -538,41 +542,55 @@
         SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig();
         if (satelliteConfig == null) {
             loge("satelliteConfig is null");
+            mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA);
             return;
         }
 
         List<String> satelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes();
         if (!isValidCountryCodes(satelliteCountryCodes)) {
             logd("country codes is invalid");
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE);
             return;
         }
 
         Boolean isSatelliteDataForAllowedRegion = satelliteConfig.isSatelliteDataForAllowedRegion();
         if (isSatelliteDataForAllowedRegion == null) {
             loge("Satellite allowed is not configured with country codes");
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE);
             return;
         }
 
         File configUpdaterS2CellFile = satelliteConfig.getSatelliteS2CellFile(context);
         if (configUpdaterS2CellFile == null || !configUpdaterS2CellFile.exists()) {
             logd("No S2 cell file configured or the file does not exist");
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE);
             return;
         }
 
         if (!isS2CellFileValid(configUpdaterS2CellFile)) {
             loge("The configured S2 cell file is not valid");
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE);
             return;
         }
 
         File localS2CellFile = copySatS2FileToLocalDirectory(configUpdaterS2CellFile);
         if (localS2CellFile == null || !localS2CellFile.exists()) {
             loge("Fail to copy S2 cell file to local directory");
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR);
             return;
         }
 
         if (!updateSharedPreferencesCountryCodes(context, satelliteCountryCodes)) {
             loge("Fail to copy country coeds into shared preferences");
             localS2CellFile.delete();
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR);
             return;
         }
 
@@ -580,6 +598,8 @@
                 context, isSatelliteDataForAllowedRegion.booleanValue())) {
             loge("Fail to copy allow access control into shared preferences");
             localS2CellFile.delete();
+            mConfigUpdaterMetricsStats.reportOemConfigError(
+                    SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR);
             return;
         }
 
@@ -599,6 +619,8 @@
             logd("clear mCachedAccessRestrictionMap");
             mCachedAccessRestrictionMap.clear();
         }
+
+        mConfigUpdaterMetricsStats.reportConfigUpdateSuccess();
     }
 
     private void loadOverlayConfigs(@NonNull Context context) {
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
index 8c2693b..d686974 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
@@ -16,8 +16,6 @@
 
 package com.android.phone.satellite.entitlement;
 
-import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
-
 import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
 import static java.time.temporal.ChronoUnit.SECONDS;
 
@@ -44,7 +42,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.ExponentialBackoff;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteConstants;
 import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.satellite.metrics.EntitlementMetricsStats;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.libraries.entitlement.ServiceEntitlementException;
 
@@ -109,6 +109,7 @@
     /** Map key : slotId, value : The last used subId. */
     @GuardedBy("mLock")
     private Map<Integer, Integer> mSubIdPerSlot = new HashMap<>();
+    @NonNull private final EntitlementMetricsStats mEntitlementMetricsStats;
 
     /**
      * Create the SatelliteEntitlementController singleton instance.
@@ -159,6 +160,7 @@
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         context.registerReceiver(mReceiver, intentFilter);
+        mEntitlementMetricsStats = EntitlementMetricsStats.getOrCreateInstance();
     }
 
     @Override
@@ -255,11 +257,15 @@
             try {
                 synchronized (mLock) {
                     mIsEntitlementInProgressPerSub.put(subId, true);
-                    mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
-                            subId).checkEntitlementStatus());
+                    SatelliteEntitlementResult entitlementResult =  getSatelliteEntitlementApi(
+                            subId).checkEntitlementStatus();
+                    mSatelliteEntitlementResultPerSub.put(subId, entitlementResult);
+                    mEntitlementMetricsStats.reportSuccess(subId,
+                            getEntitlementStatus(entitlementResult), false);
                 }
             } catch (ServiceEntitlementException e) {
                 loge(e.toString());
+                mEntitlementMetricsStats.reportError(subId, e.getErrorCode(), false);
                 if (!isInternetConnected()) {
                     logd("StartQuery: disconnected. " + e);
                     synchronized (mLock) {
@@ -319,11 +325,15 @@
                 int currentRetryCount = getRetryCount(subId);
                 mRetryCountPerSub.put(subId, currentRetryCount + 1);
                 logd("[" + subId + "] retry cnt:" + getRetryCount(subId));
-                mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
-                        subId).checkEntitlementStatus());
+                SatelliteEntitlementResult entitlementResult =  getSatelliteEntitlementApi(
+                        subId).checkEntitlementStatus();
+                mSatelliteEntitlementResultPerSub.put(subId, entitlementResult);
+                mEntitlementMetricsStats.reportSuccess(subId,
+                        getEntitlementStatus(entitlementResult), true);
             }
         } catch (ServiceEntitlementException e) {
             loge(e.toString());
+            mEntitlementMetricsStats.reportError(subId, e.getErrorCode(), true);
             if (!isRetryAvailable(subId)) {
                 logd("retryQuery: unavailable.");
                 queryCompleted(subId);
@@ -464,8 +474,8 @@
         sendMessageDelayed(message, TimeUnit.DAYS.toMillis(
                 getSatelliteEntitlementStatusRefreshDays(subId)));
         logd("queryCompleted: updateSatelliteEntitlementStatus");
-        updateSatelliteEntitlementStatus(subId,
-                entitlementResult.getEntitlementStatus() == SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+        updateSatelliteEntitlementStatus(subId, entitlementResult.getEntitlementStatus() ==
+                        SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED,
                 entitlementResult.getAllowedPLMNList(), entitlementResult.getBarredPLMNList());
     }
 
@@ -511,12 +521,13 @@
     private void resetSatelliteEntitlementRestrictedReason(int subId) {
         SatelliteEntitlementResult previousResult;
         SatelliteEntitlementResult enabledResult = new SatelliteEntitlementResult(
-                SATELLITE_ENTITLEMENT_STATUS_ENABLED, new ArrayList<>(), new ArrayList<>());
+                SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+                new ArrayList<>(), new ArrayList<>());
         synchronized (mLock) {
             previousResult = mSatelliteEntitlementResultPerSub.get(subId);
         }
         if (previousResult != null && previousResult.getEntitlementStatus()
-                != SATELLITE_ENTITLEMENT_STATUS_ENABLED) {
+                != SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED) {
             logd("set enabled status for removing satellite entitlement restricted reason");
             synchronized (mLock) {
                 mSatelliteEntitlementResultPerSub.put(subId, enabledResult);
@@ -633,6 +644,22 @@
                 plmnAllowedList, plmnBarredList, null);
     }
 
+    private @SatelliteConstants.SatelliteEntitlementStatus int getEntitlementStatus(
+            SatelliteEntitlementResult entitlementResult) {
+        switch (entitlementResult.getEntitlementStatus()) {
+            case SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED:
+                return SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+            case SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED:
+                return SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+            case SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE:
+                return SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE;
+            case SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_PROVISIONING:
+                return SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_PROVISIONING;
+            default:
+                return SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_UNKNOWN;
+        }
+    }
+
     private static void logd(String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 3fb6ae8..099def8 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -333,6 +333,9 @@
         }
 
         if (result.getAccessNetwork() == UNKNOWN) {
+            if (maybeRedialOnTheOtherSlotInNormalService(mLastRegResult)) {
+                return;
+            }
             if ((mPreferredNetworkScanType == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)
                       && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
                 mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
@@ -358,6 +361,13 @@
             return;
         }
 
+        if (result.getRegState() != REGISTRATION_STATE_HOME
+                && result.getRegState() != REGISTRATION_STATE_ROAMING) {
+            if (maybeRedialOnTheOtherSlotInNormalService(result)) {
+                return;
+            }
+        }
+
         mLastRegResult = result;
         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
         onWwanNetworkTypeSelected(getAccessNetworkType(result));
@@ -856,7 +866,7 @@
         boolean psInService = isPsInService();
 
         if (!csInService && !psInService) {
-            if (maybeRedialOnTheOtherSlotInNormalService()) {
+            if (maybeRedialOnTheOtherSlotInNormalService(mLastRegResult)) {
                 return;
             }
             mCsNetworkType = getSelectableCsNetworkType();
@@ -1647,14 +1657,28 @@
         return true;
     }
 
-    private boolean maybeRedialOnTheOtherSlotInNormalService() {
-        EmergencyRegistrationResult regResult =
-                mSelectionAttributes.getEmergencyRegistrationResult();
+    private String getCountryIso(String iso) {
+        if (TextUtils.isEmpty(iso)) {
+            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+            iso = tm.getNetworkCountryIso(getSlotId());
+            if (TextUtils.isEmpty(iso)) {
+                for (int i = 0; i < mModemCount; i++) {
+                    iso = tm.getNetworkCountryIso(i);
+                    if (!TextUtils.isEmpty(iso)) break;
+                }
+            }
+        }
+        return iso;
+    }
+
+    private boolean maybeRedialOnTheOtherSlotInNormalService(
+            EmergencyRegistrationResult regResult) {
         if (regResult == null) return false;
 
-        String iso = regResult.getCountryIso();
+        String iso = getCountryIso(regResult.getCountryIso());
         if (sPreferSlotWithNormalServiceList.contains(iso)
                 && mCrossSimRedialingController.isThereOtherSlotInService()) {
+            logi("maybeRedialOnTheOtherSlotInNormalService");
             terminateSelectionForCrossSimRedialing(false);
             return true;
         }
@@ -1678,6 +1702,8 @@
     }
 
     private void terminateSelection(int cause) {
+        removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
+        removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
         mTransportSelectorCallback.onSelectionTerminated(cause);
     }
 
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 4690d6e..38c9677 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -1880,6 +1880,39 @@
     }
 
     @Test
+    public void testDualSimNormalServiceOnTheOtherSubscriptionAfterScan() throws Exception {
+        mResultConsumer = null;
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
+        doReturn(true).when(mCsrdCtrl).isThereOtherSlotInService();
+        doReturn(new String[] {"in"}).when(mResources).getStringArray(anyInt());
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(UNKNOWN,
+                REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), eq(false), any(), any());
+        assertNotNull(mResultConsumer);
+
+        regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "", "in");
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, times(1))
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+    }
+
+    @Test
     public void testEutranWithCsDomainOnly() throws Exception {
         setupForHandleScanResult();