Merge "Update PhoneGlobals.java to inject feature flag to ImsResolver" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1190d38..97f5858 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -119,6 +119,7 @@
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+    <uses-permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER" />
     <!-- Needed to block messages. -->
     <uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS" />
     <!-- Needed for emergency contact notification. -->
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index fc0ed0e..c494e7c 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -844,7 +844,7 @@
     <string name="removable_esim_string" msgid="7931369811671787649">"Чыгарылуучу eSIM-картаны демейки катары коюу"</string>
     <string name="radio_info_radio_power" msgid="8805595022160471587">"Мобилдик радионун кубаты"</string>
     <string name="simulate_out_of_service_string" msgid="7787925611727597193">"Тейлөө аймагынын сыртында режимин иштетүү (Мүчүлүштүктөрдү оңдоо үчүн гана)"</string>
-    <string name="mock_carrier_roaming_satellite_string" msgid="4796300252858292593">"Жалган байланыш оператору спутниги (Мүчүлүштүктөрдү оңдоо үчүн гана)"</string>
+    <string name="mock_carrier_roaming_satellite_string" msgid="4796300252858292593">"Симуляцияланган байланыш операторунун спутниги (Мүчүлүштүктөрдү оңдоо үчүн гана)"</string>
     <string name="radioInfo_menu_viewADN" msgid="4533179730908559846">"SIM картадагы дарек китепчесин көрүү"</string>
     <string name="radioInfo_menu_viewFDN" msgid="1847236480527032061">"Туруктуу терүү номерлерин көрүү"</string>
     <string name="radioInfo_menu_viewSDN" msgid="2613431584522392842">"Кызматтык терүү номерлерин көрүү"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 9b71919..47fd96e 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -47,6 +47,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
 import android.service.carrier.CarrierIdentifier;
@@ -698,6 +699,7 @@
     @NonNull private final FeatureFlags  mFeatureFlags;
 
     @NonNull private final PackageManager mPackageManager;
+    private final int mVendorApiLevel;
 
     /**
      * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
@@ -736,6 +738,8 @@
         }
         mFeatureFlags = featureFlags;
         mPackageManager = context.getPackageManager();
+        mVendorApiLevel = SystemProperties.getInt(
+                "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
         logd("CarrierConfigLoader has started");
 
         PhoneConfigurationManager.registerForMultiSimConfigChange(
@@ -1884,7 +1888,11 @@
 
         if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
                 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
-                Binder.getCallingUserHandle())) {
+                Binder.getCallingUserHandle())
+                || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+            // Skip to check associated telephony feature,
+            // if compatibility change is not enabled for the current process or
+            // the SDK version of vendor partition is less than Android V.
             return;
         }
 
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index a778f6a..766d719 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -32,6 +32,7 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -85,6 +86,7 @@
     private PackageManager mPackageManager;
     // set by shell cmd phone src set-device-enabled true/false
     private Boolean mSingleRegistrationOverride;
+    private final int mVendorApiLevel;
 
     /**
      * For apps targeting Android T and above, support the publishing state on APIs, such as
@@ -119,6 +121,8 @@
         TelephonyFrameworkInitializer
                 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
         mImsResolver = ImsResolver.getInstance();
+        mVendorApiLevel = SystemProperties.getInt(
+                "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
     }
 
     /**
@@ -1000,7 +1004,11 @@
 
         if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
                 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
-                Binder.getCallingUserHandle())) {
+                Binder.getCallingUserHandle())
+                || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+            // Skip to check associated telephony feature,
+            // if compatibility change is not enabled for the current process or
+            // the SDK version of vendor partition is less than Android V.
             return;
         }
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 2779bdb..9e5461c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -76,6 +76,7 @@
 import android.os.ResultReceiver;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
@@ -437,6 +438,7 @@
     private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
     private AppOpsManager mAppOps;
     private PackageManager mPackageManager;
+    private final int mVendorApiLevel;
 
     /** User Activity */
     private final AtomicBoolean mNotifyUserActivity;
@@ -2482,6 +2484,9 @@
         mPackageManager = app.getPackageManager();
         mSatelliteAccessController = SatelliteAccessController.getOrCreateInstance(
                 getDefaultPhone().getContext(), featureFlags);
+        mVendorApiLevel = SystemProperties.getInt(
+                "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
+
         PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
         publish();
         CarrierAllowListInfo.loadInstance(mApp);
@@ -14096,7 +14101,11 @@
 
         if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
                 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
-                Binder.getCallingUserHandle())) {
+                Binder.getCallingUserHandle())
+                || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+            // Skip to check associated telephony feature,
+            // if compatibility change is not enabled for the current process or
+            // the SDK version of vendor partition is less than Android V.
             return;
         }
 
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
index d193a7d..8c2693b 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
@@ -40,6 +40,7 @@
 import android.telephony.SubscriptionManager;
 
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.ExponentialBackoff;
 import com.android.internal.telephony.flags.FeatureFlags;
@@ -49,6 +50,7 @@
 
 import java.time.Instant;
 import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -65,7 +67,6 @@
     /** Message code used in handleMessage() */
     private static final int CMD_START_QUERY_ENTITLEMENT = 1;
     private static final int CMD_RETRY_QUERY_ENTITLEMENT = 2;
-    private static final int CMD_STOP_RETRY_QUERY_ENTITLEMENT = 3;
 
     /** Retry on next trigger event. */
     private static final int HTTP_RESPONSE_500 = 500;
@@ -74,7 +75,7 @@
     private static final int HTTP_RESPONSE_503 = 503;
     /** Default query refresh time is 1 month. */
 
-    private static final int DEFAULT_QUERY_REFRESH_DAYS = 30;
+    private static final int DEFAULT_QUERY_REFRESH_DAYS = 7;
     private static final long INITIAL_DELAY_MILLIS = TimeUnit.MINUTES.toMillis(10); // 10 min
     private static final long MAX_DELAY_MILLIS = TimeUnit.DAYS.toMillis(5); // 5 days
     private static final int MULTIPLIER = 2;
@@ -89,15 +90,25 @@
     @NonNull private final Context mContext;
     private final Object mLock = new Object();
     /** Map key : subId, value : ExponentialBackoff. */
+    @GuardedBy("mLock")
     private Map<Integer, ExponentialBackoff> mExponentialBackoffPerSub = new HashMap<>();
     /** Map key : subId, value : SatelliteEntitlementResult. */
+    @GuardedBy("mLock")
     private Map<Integer, SatelliteEntitlementResult> mSatelliteEntitlementResultPerSub =
             new HashMap<>();
     /** Map key : subId, value : the last query time to millis. */
+    @GuardedBy("mLock")
     private Map<Integer, Long> mLastQueryTimePerSub = new HashMap<>();
     /** Map key : subId, value : Count the number of retries caused by the 'ExponentialBackoff' and
      * '503 error case with the Retry-After header'. */
+    @GuardedBy("mLock")
     private Map<Integer, Integer> mRetryCountPerSub = new HashMap<>();
+    /** Map key : subId, value : Whether query is in progress. */
+    @GuardedBy("mLock")
+    private Map<Integer, Boolean> mIsEntitlementInProgressPerSub = new HashMap<>();
+    /** Map key : slotId, value : The last used subId. */
+    @GuardedBy("mLock")
+    private Map<Integer, Integer> mSubIdPerSlot = new HashMap<>();
 
     /**
      * Create the SatelliteEntitlementController singleton instance.
@@ -140,11 +151,6 @@
             public void onAvailable(Network network) {
                 handleInternetConnected();
             }
-
-            @Override
-            public void onLost(Network network) {
-                handleInternetDisconnected();
-            }
         };
         NetworkRequest networkrequest = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
@@ -164,9 +170,6 @@
             case CMD_RETRY_QUERY_ENTITLEMENT:
                 handleCmdRetryQueryEntitlement(msg.arg1);
                 break;
-            case CMD_STOP_RETRY_QUERY_ENTITLEMENT:
-                stopExponentialBackoff(msg.arg1);
-                break;
             default:
                 logd("do not used this message");
         }
@@ -174,14 +177,35 @@
 
     private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId,
             int specificCarrierId) {
-        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            return;
-        }
         logd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId("
                 + subId + "), carrierId(" + carrierId + "), specificCarrierId("
                 + specificCarrierId + ")");
+        processSimChanged(slotIndex, subId);
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return;
+        }
 
         sendEmptyMessage(CMD_START_QUERY_ENTITLEMENT);
+        synchronized (mLock) {
+            mSubIdPerSlot.put(slotIndex, subId);
+        }
+    }
+
+    // When SIM is removed or changed, then reset the previous subId's retry related objects.
+    private void processSimChanged(int slotIndex, int subId) {
+        int previousSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        synchronized (mLock) {
+            previousSubId = mSubIdPerSlot.getOrDefault(slotIndex,
+                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        }
+        logd("processSimChanged prev subId:" + previousSubId);
+        if (previousSubId != subId) {
+            synchronized (mLock) {
+                mSubIdPerSlot.remove(slotIndex);
+            }
+            logd("processSimChanged resetEntitlementQueryPerSubId");
+            resetEntitlementQueryPerSubId(previousSubId);
+        }
     }
 
     private class SatelliteEntitlementControllerReceiver extends BroadcastReceiver {
@@ -214,15 +238,6 @@
         sendEmptyMessage(CMD_START_QUERY_ENTITLEMENT);
     }
 
-    private void handleInternetDisconnected() {
-        mExponentialBackoffPerSub.forEach((key, value) -> {
-            Message message = obtainMessage();
-            message.what = CMD_STOP_RETRY_QUERY_ENTITLEMENT;
-            message.arg1 = key;
-            sendMessage(message);
-        });
-    }
-
     /**
      * Check if the device can request to entitlement server (if there is an internet connection and
      * if the throttle time has passed since the last request), and then pass the response to
@@ -230,34 +245,44 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public void handleCmdStartQueryEntitlement() {
-        if (!isInternetConnected()) {
-            logd("Internet disconnected");
-            return;
-        }
-
         for (int subId : mSubscriptionManagerService.getActiveSubIdList(true)) {
-            if (!shouldQueryEntitlement(subId)) {
-                return;
+            if (!shouldStartQueryEntitlement(subId)) {
+                continue;
             }
 
             // Check the satellite service query result from the entitlement server for the
             // satellite service.
             try {
-                mSatelliteEntitlementResultPerSub.remove(subId);
-                mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
-                        subId).checkEntitlementStatus());
+                synchronized (mLock) {
+                    mIsEntitlementInProgressPerSub.put(subId, true);
+                    mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
+                            subId).checkEntitlementStatus());
+                }
             } catch (ServiceEntitlementException e) {
                 loge(e.toString());
                 if (!isInternetConnected()) {
-                    logd("handleCmdStartQueryEntitlement: disconnected. " + e);
+                    logd("StartQuery: disconnected. " + e);
+                    synchronized (mLock) {
+                        mIsEntitlementInProgressPerSub.remove(subId);
+                    }
                     return;
                 }
-                if (shouldHandleErrorResponse(e, subId)) {
-                    logd("handleCmdStartQueryEntitlement: handle response.");
-                    return;
+                if (isPermanentError(e)) {
+                    logd("StartQuery: shouldPermanentError.");
+                    queryCompleted(subId);
+                    continue;
+                } else if (isRetryAfterError(e)) {
+                    long retryAfterSeconds = parseSecondsFromRetryAfter(e.getRetryAfter());
+                    logd("StartQuery: next retry will be in " + TimeUnit.SECONDS.toMillis(
+                            retryAfterSeconds) + " sec");
+                    sendMessageDelayed(obtainMessage(CMD_RETRY_QUERY_ENTITLEMENT, subId, 0),
+                            TimeUnit.SECONDS.toMillis(retryAfterSeconds));
+                    stopExponentialBackoff(subId);
+                    continue;
+                } else {
+                    startExponentialBackoff(subId);
+                    continue;
                 }
-                startExponentialBackoff(subId);
-                return;
             }
             queryCompleted(subId);
         }
@@ -267,9 +292,12 @@
      * query. */
     private void resetEntitlementQueryCounts(String event) {
         logd("resetEntitlementQueryCounts: " + event);
-        mLastQueryTimePerSub = new HashMap<>();
-        mExponentialBackoffPerSub = new HashMap<>();
-        mRetryCountPerSub = new HashMap<>();
+        synchronized (mLock) {
+            mLastQueryTimePerSub = new HashMap<>();
+            mExponentialBackoffPerSub = new HashMap<>();
+            mRetryCountPerSub = new HashMap<>();
+            mIsEntitlementInProgressPerSub = new HashMap<>();
+        }
     }
 
     /**
@@ -283,65 +311,79 @@
      * MAX_RETRY_COUNT is reached using the ExponentialBackoff.
      */
     private void handleCmdRetryQueryEntitlement(int subId) {
-        logd("handleCmdRetryQueryEntitlement: " + subId);
+        if (!shouldRetryQueryEntitlement(subId)) {
+            return;
+        }
         try {
             synchronized (mLock) {
+                int currentRetryCount = getRetryCount(subId);
+                mRetryCountPerSub.put(subId, currentRetryCount + 1);
+                logd("[" + subId + "] retry cnt:" + getRetryCount(subId));
                 mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
                         subId).checkEntitlementStatus());
             }
         } catch (ServiceEntitlementException e) {
+            loge(e.toString());
+            if (!isRetryAvailable(subId)) {
+                logd("retryQuery: unavailable.");
+                queryCompleted(subId);
+                return;
+            }
             if (!isInternetConnected()) {
-                logd("retryQuery: Internet disconnected. reset the retry and after the "
-                        + "internet is connected then the first query is triggered." + e);
+                logd("retryQuery: Internet disconnected.");
                 stopExponentialBackoff(subId);
+                synchronized (mLock) {
+                    mIsEntitlementInProgressPerSub.remove(subId);
+                }
                 return;
             }
-            if (shouldHandleErrorResponse(e, subId)) {
-                logd("retryQuery: handle response.");
+            if (isPermanentError(e)) {
+                logd("retryQuery: shouldPermanentError.");
+                queryCompleted(subId);
+                return;
+            } else if (isRetryAfterError(e)) {
+                long retryAfterSeconds = parseSecondsFromRetryAfter(e.getRetryAfter());
+                logd("retryQuery: next retry will be in " + TimeUnit.SECONDS.toMillis(
+                        retryAfterSeconds) + " sec");
+                sendMessageDelayed(obtainMessage(CMD_RETRY_QUERY_ENTITLEMENT, subId, 0),
+                        TimeUnit.SECONDS.toMillis(retryAfterSeconds));
                 stopExponentialBackoff(subId);
                 return;
+            } else {
+                ExponentialBackoff exponentialBackoff = null;
+                synchronized (mLock) {
+                    exponentialBackoff = mExponentialBackoffPerSub.get(subId);
+                }
+                if (exponentialBackoff == null) {
+                    startExponentialBackoff(subId);
+                } else {
+                    exponentialBackoff.notifyFailed();
+                    logd("retryQuery: The next retry will be in "
+                            + exponentialBackoff.getCurrentDelay() + " ms.");
+                }
+                return;
             }
-            mExponentialBackoffPerSub.get(subId).notifyFailed();
-            mRetryCountPerSub.put(subId,
-                    mRetryCountPerSub.getOrDefault(subId, 0) + 1);
-            logd("handleCmdRetryQueryEntitlement:" + e + "[" + subId + "] cnt="
-                    + mRetryCountPerSub.getOrDefault(subId, 0) + "] Retrying in "
-                    + mExponentialBackoffPerSub.get(subId).getCurrentDelay() + " ms.");
         }
+        queryCompleted(subId);
     }
 
-    /** Only handle '500' and '503 with retry-after header' error responses received.
-     * If the 500 response is received, no retry until the next trigger event occurs.
-     * If the 503 response with Retry-After header, retry is attempted according to the value in the
-     * Retry-After header up to MAX_RETRY_COUNT.
-     * In other cases, it performs an exponential backoff process. */
-    private boolean shouldHandleErrorResponse(ServiceEntitlementException e, int subId) {
+    // If the 500 response is received, no retry until the next trigger event occurs.
+    private boolean isPermanentError(ServiceEntitlementException e) {
+        return e.getHttpStatus() == HTTP_RESPONSE_500;
+    }
+
+    /** If the 503 response with Retry-After header, retry is attempted according to the value in
+     * the Retry-After header up to MAX_RETRY_COUNT. */
+    private boolean isRetryAfterError(ServiceEntitlementException e) {
         int responseCode = e.getHttpStatus();
-        logd("shouldHandleErrorResponse: received the " + responseCode);
+        logd("shouldRetryAfterError: received the " + responseCode);
         if (responseCode == HTTP_RESPONSE_503 && e.getRetryAfter() != null
                 && !e.getRetryAfter().isEmpty()) {
-            if (mRetryCountPerSub.getOrDefault(subId, 0) >= MAX_RETRY_COUNT) {
-                logd("The 503 retry after reaching the " + MAX_RETRY_COUNT
-                        + "The retry will not be attempted until the next trigger event.");
-                queryCompleted(subId);
-                return true;
-            }
             long retryAfterSeconds = parseSecondsFromRetryAfter(e.getRetryAfter());
             if (retryAfterSeconds == -1) {
                 logd("Unable parsing the retry-after. try to exponential backoff.");
                 return false;
             }
-            mRetryCountPerSub.put(subId, mRetryCountPerSub.getOrDefault(subId, 0) + 1);
-            logd("[" + subId + "] cnt=" + mRetryCountPerSub.getOrDefault(subId, 0)
-                    + " Retrying in " + TimeUnit.SECONDS.toMillis(retryAfterSeconds) + " sec");
-            Message message = obtainMessage();
-            message.what = CMD_RETRY_QUERY_ENTITLEMENT;
-            message.arg1 = subId;
-            sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(retryAfterSeconds));
-            return true;
-        } else if (responseCode == HTTP_RESPONSE_500) {
-            logd("The retry on the next trigger event.");
-            queryCompleted(subId);
             return true;
         }
         return false;
@@ -364,46 +406,34 @@
     }
 
     private void startExponentialBackoff(int subId) {
+        ExponentialBackoff exponentialBackoff = null;
         stopExponentialBackoff(subId);
-        mExponentialBackoffPerSub.put(subId,
-                new ExponentialBackoff(INITIAL_DELAY_MILLIS, MAX_DELAY_MILLIS,
-                        MULTIPLIER, this.getLooper(), () -> {
-                    synchronized (mLock) {
-                        if (mSatelliteEntitlementResultPerSub.containsKey(subId)) {
-                            logd("handleCmdStartQueryEntitlement: get the response "
-                                    + "successfully.");
-                            mExponentialBackoffPerSub.get(subId).stop();
-                            queryCompleted(subId);
-                            return;
+        synchronized (mLock) {
+            mExponentialBackoffPerSub.put(subId,
+                    new ExponentialBackoff(INITIAL_DELAY_MILLIS, MAX_DELAY_MILLIS,
+                            MULTIPLIER, this.getLooper(), () -> {
+                        synchronized (mLock) {
+                            sendMessage(obtainMessage(CMD_RETRY_QUERY_ENTITLEMENT, subId, 0));
                         }
-
-                        if (mRetryCountPerSub.getOrDefault(subId, 0) >= MAX_RETRY_COUNT) {
-                            logd("The ExponentialBackoff is  stopped after reaching the "
-                                    + MAX_RETRY_COUNT + ". The retry don't attempted until the"
-                                    + " refresh time expires.");
-                            mExponentialBackoffPerSub.get(subId).stop();
-                            queryCompleted(subId);
-                            return;
-                        }
-                        if (!mSatelliteEntitlementResultPerSub.containsKey(subId)) {
-                            handleCmdRetryQueryEntitlement(subId);
-                        }
-                    }
-                }));
-        mExponentialBackoffPerSub.get(subId).start();
-        mRetryCountPerSub.put(subId, mRetryCountPerSub.getOrDefault(subId, 0) + 1);
-        logd("start ExponentialBackoff [" + mRetryCountPerSub.getOrDefault(subId, 0)
-                + "] Retrying in " + mExponentialBackoffPerSub.get(subId).getCurrentDelay()
-                + " ms.");
+                    }));
+            exponentialBackoff = mExponentialBackoffPerSub.get(subId);
+        }
+        if (exponentialBackoff != null) {
+            exponentialBackoff.start();
+            logd("start ExponentialBackoff, cnt: " + getRetryCount(subId) + ". Retrying in "
+                    + exponentialBackoff.getCurrentDelay() + " ms.");
+        }
     }
 
     /** If the Internet connection is lost during the ExponentialBackoff, stop the
      * ExponentialBackoff and reset it. */
     private void stopExponentialBackoff(int subId) {
-        if (isExponentialBackoffInProgress(subId)) {
-            logd("stopExponentialBackoff: reset ExponentialBackoff");
-            mExponentialBackoffPerSub.get(subId).stop();
-            mExponentialBackoffPerSub.remove(subId);
+        synchronized (mLock) {
+            if (mExponentialBackoffPerSub.get(subId) != null) {
+                logd("stopExponentialBackoff: reset ExponentialBackoff");
+                mExponentialBackoffPerSub.get(subId).stop();
+                mExponentialBackoffPerSub.remove(subId);
+            }
         }
     }
 
@@ -413,10 +443,18 @@
      * And then it send a delayed message to trigger the query again after A refresh day has passed.
      */
     private void queryCompleted(int subId) {
-        if (!mSatelliteEntitlementResultPerSub.containsKey(subId)) {
-            logd("queryCompleted: create default SatelliteEntitlementResult");
-            mSatelliteEntitlementResultPerSub.put(subId,
-                    SatelliteEntitlementResult.getDefaultResult());
+        SatelliteEntitlementResult entitlementResult;
+        synchronized (mLock) {
+            if (!mSatelliteEntitlementResultPerSub.containsKey(subId)) {
+                logd("queryCompleted: create default SatelliteEntitlementResult");
+                mSatelliteEntitlementResultPerSub.put(subId,
+                        SatelliteEntitlementResult.getDefaultResult());
+            }
+            entitlementResult = mSatelliteEntitlementResultPerSub.get(subId);
+            stopExponentialBackoff(subId);
+            mIsEntitlementInProgressPerSub.remove(subId);
+            logd("reset retry count for refresh query");
+            mRetryCountPerSub.remove(subId);
         }
 
         saveLastQueryTime(subId);
@@ -427,35 +465,78 @@
                 getSatelliteEntitlementStatusRefreshDays(subId)));
         logd("queryCompleted: updateSatelliteEntitlementStatus");
         updateSatelliteEntitlementStatus(subId,
-                mSatelliteEntitlementResultPerSub.get(subId).getEntitlementStatus()
-                        == SATELLITE_ENTITLEMENT_STATUS_ENABLED,
-                mSatelliteEntitlementResultPerSub.get(subId).getAllowedPLMNList(),
-                mSatelliteEntitlementResultPerSub.get(subId).getBarredPLMNList());
-        stopExponentialBackoff(subId);
-        mRetryCountPerSub.remove(subId);
+                entitlementResult.getEntitlementStatus() == SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+                entitlementResult.getAllowedPLMNList(), entitlementResult.getBarredPLMNList());
     }
 
-    /** Check whether there is a saved subId. Returns true if there is a saved subId,
-     * otherwise return false.*/
-    private boolean isExponentialBackoffInProgress(int subId) {
-        return mExponentialBackoffPerSub.containsKey(subId);
+    private boolean shouldStartQueryEntitlement(int subId) {
+        logd("shouldStartQueryEntitlement " + subId);
+        if (!shouldRetryQueryEntitlement(subId)) {
+            return false;
+        }
+
+        synchronized (mLock) {
+            if (mIsEntitlementInProgressPerSub.getOrDefault(subId, false)) {
+                logd("In progress retry");
+                return false;
+            }
+        }
+        return true;
     }
 
-    /**
-     * Check if the subId can query the entitlement server to get the satellite configuration.
-     */
-    private boolean shouldQueryEntitlement(int subId) {
+    private boolean shouldRetryQueryEntitlement(int subId) {
         if (!isSatelliteEntitlementSupported(subId)) {
             logd("Doesn't support entitlement query for satellite.");
+            resetSatelliteEntitlementRestrictedReason(subId);
             return false;
         }
 
-        if (isExponentialBackoffInProgress(subId)) {
-            logd("In progress ExponentialBackoff.");
+        if (!isInternetConnected()) {
+            stopExponentialBackoff(subId);
+            synchronized (mLock) {
+                mIsEntitlementInProgressPerSub.remove(subId);
+            }
+            logd("Internet disconnected");
             return false;
         }
 
-        return shouldRefreshEntitlementStatus(subId);
+        if (!shouldRefreshEntitlementStatus(subId)) {
+            return false;
+        }
+
+        return isRetryAvailable(subId);
+    }
+
+    // update for removing the satellite entitlement restricted reason
+    private void resetSatelliteEntitlementRestrictedReason(int subId) {
+        SatelliteEntitlementResult previousResult;
+        SatelliteEntitlementResult enabledResult = new SatelliteEntitlementResult(
+                SATELLITE_ENTITLEMENT_STATUS_ENABLED, new ArrayList<>(), new ArrayList<>());
+        synchronized (mLock) {
+            previousResult = mSatelliteEntitlementResultPerSub.get(subId);
+        }
+        if (previousResult != null && previousResult.getEntitlementStatus()
+                != SATELLITE_ENTITLEMENT_STATUS_ENABLED) {
+            logd("set enabled status for removing satellite entitlement restricted reason");
+            synchronized (mLock) {
+                mSatelliteEntitlementResultPerSub.put(subId, enabledResult);
+            }
+            updateSatelliteEntitlementStatus(subId, true, enabledResult.getAllowedPLMNList(),
+                    enabledResult.getBarredPLMNList());
+        }
+        resetEntitlementQueryPerSubId(subId);
+    }
+
+    private void resetEntitlementQueryPerSubId(int subId) {
+        logd("resetEntitlementQueryPerSubId: " + subId);
+        stopExponentialBackoff(subId);
+        synchronized (mLock) {
+            mLastQueryTimePerSub.remove(subId);
+            mRetryCountPerSub.remove(subId);
+            mIsEntitlementInProgressPerSub.remove(subId);
+        }
+        removeMessages(CMD_RETRY_QUERY_ENTITLEMENT,
+                obtainMessage(CMD_RETRY_QUERY_ENTITLEMENT, subId, 0));
     }
 
     /**
@@ -489,7 +570,9 @@
     /** If there is a value stored in the cache, it is used. If there is no value stored in the
      * cache, it is considered the first query. */
     private long getLastQueryTime(int subId) {
-        return mLastQueryTimePerSub.getOrDefault(subId, 0L);
+        synchronized (mLock) {
+            return mLastQueryTimePerSub.getOrDefault(subId, 0L);
+        }
     }
 
     /** Return the satellite entitlement status refresh days from carrier config. */
@@ -499,6 +582,14 @@
                 DEFAULT_QUERY_REFRESH_DAYS);
     }
 
+    private boolean isRetryAvailable(int subId) {
+        if (getRetryCount(subId) >= MAX_RETRY_COUNT) {
+            logd("The retry will not be attempted until the next trigger event.");
+            return false;
+        }
+        return true;
+    }
+
     /** Return the satellite entitlement supported bool from carrier config. */
     private boolean isSatelliteEntitlementSupported(int subId) {
         return getConfigForSubId(subId).getBoolean(
@@ -520,7 +611,15 @@
 
     private void saveLastQueryTime(int subId) {
         long lastQueryTimeMillis = System.currentTimeMillis();
-        mLastQueryTimePerSub.put(subId, lastQueryTimeMillis);
+        synchronized (mLock) {
+            mLastQueryTimePerSub.put(subId, lastQueryTimeMillis);
+        }
+    }
+
+    private int getRetryCount(int subId) {
+        synchronized (mLock) {
+            return mRetryCountPerSub.getOrDefault(subId, 0);
+        }
     }
 
     /**
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 064c69b..77bc32a 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -1687,6 +1687,21 @@
                             continue;
                         }
 
+                        // Skip the sim for bootstrap
+                        if (info.getProfileClass() == SubscriptionManager
+                                .PROFILE_CLASS_PROVISIONING) {
+                            Log.d(this, "setupAccounts: skipping bootstrap sub id "
+                                    + subscriptionId);
+                            continue;
+                        }
+
+                        // Skip the sim for satellite as it does not support call for now
+                        if (Flags.oemEnabledSatelliteFlag() && info.isOnlyNonTerrestrialNetwork()) {
+                            Log.d(this, "setupAccounts: skipping satellite sub id "
+                                    + subscriptionId);
+                            continue;
+                        }
+
                         mAccounts.add(new AccountEntry(phone, false /* emergency */,
                                 false /* isTest */));
                     }
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 29ad29e..e82bf67 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -447,12 +447,14 @@
 
         if (mLastNetworkType == EUTRAN && mLastRegResult != null
                 && mSelectionAttributes.getPsDisconnectCause() != null
+                && !mScanLimitedOnlyAfterVolteFailure
                 && !mSwitchRatPreferenceWithLocalNotRegistered) {
             int regState = mLastRegResult.getRegState();
             int reasonCode = mSelectionAttributes.getPsDisconnectCause().getCode();
             if (reasonCode == ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED
                     && regState != REGISTRATION_STATE_HOME
-                    && regState != REGISTRATION_STATE_ROAMING) {
+                    && regState != REGISTRATION_STATE_ROAMING
+                    && isSimReady()) {
                 // b/326292100, ePDN setup failed in limited state, request PS preferred scan.
                 mLastNetworkType = UNKNOWN;
                 mSwitchRatPreferenceWithLocalNotRegistered = true;
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index f4197d9..bda2313 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -429,11 +429,16 @@
 
     @Test
     @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
-    public void testGetConfigForSubIdWithFeature_withTelephonyFeatureMapping() {
+    public void testGetConfigForSubIdWithFeature_withTelephonyFeatureMapping() throws Exception {
         doNothing().when(mContext).enforcePermission(
                 eq(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE),
                 anyInt(), anyInt(), anyString());
 
+        // Replace field to set SDK version of vendor partition to Android V
+        int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+        replaceInstance(CarrierConfigLoader.class, "mVendorApiLevel", mCarrierConfigLoader,
+                vendorApiLevel);
+
         doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
         doReturn(false).when(mPackageManager).hasSystemFeature(
                 eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index bd47b94..2d46c80 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -40,6 +40,7 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.os.Build;
 import android.permission.flags.Flags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.RadioAccessFamily;
@@ -67,7 +68,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Locale;
 
 /**
@@ -499,6 +499,11 @@
     @Test
     @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
     public void testWithoutTelephonyFeatureAndCompatChanges() throws Exception {
+        // Replace field to set SDK version of vendor partition to Android V
+        int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+        replaceInstance(PhoneInterfaceManager.class, "mVendorApiLevel", mPhoneInterfaceManager,
+                vendorApiLevel);
+
         // telephony features is not defined, expect UnsupportedOperationException.
         doReturn(false).when(mPackageManager).hasSystemFeature(
                 PackageManager.FEATURE_TELEPHONY_CALLING);
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
index dd9ea65..4dcef2a 100644
--- a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
@@ -16,8 +16,13 @@
 
 package com.android.phone.satellite.entitlement;
 
+import static com.android.libraries.entitlement.ServiceEntitlementException.ERROR_HTTP_STATUS_NOT_SUCCESS;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
 import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -29,8 +34,11 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -55,6 +63,7 @@
 import com.android.internal.telephony.ExponentialBackoff;
 import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
+import com.android.libraries.entitlement.ServiceEntitlementException;
 
 import org.junit.After;
 import org.junit.Before;
@@ -62,6 +71,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -70,6 +81,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 public class SatelliteEntitlementControllerTest extends TelephonyTestBase {
@@ -77,9 +89,13 @@
     private static final int SUB_ID = 0;
     private static final int SUB_ID_2 = 1;
     private static final int[] ACTIVE_SUB_ID = {SUB_ID};
-    private static final int DEFAULT_QUERY_REFRESH_DAY = 30;
+    private static final int DEFAULT_QUERY_REFRESH_DAY = 7;
     private static final List<String> PLMN_ALLOWED_LIST = Arrays.asList("31026", "302820");
     private static final List<String> PLMN_BARRED_LIST = Arrays.asList("12345", "98765");
+    private static final List<String> EMPTY_PLMN_LIST = new ArrayList<>();
+    private static final int CMD_START_QUERY_ENTITLEMENT = 1;
+    private static final int CMD_RETRY_QUERY_ENTITLEMENT = 2;
+    private static final int MAX_RETRY_COUNT = 5;
     @Mock
     CarrierConfigManager mCarrierConfigManager;
     @Mock
@@ -90,7 +106,6 @@
     @Mock SatelliteEntitlementApi mSatelliteEntitlementApi;
     @Mock SatelliteEntitlementResult mSatelliteEntitlementResult;
     @Mock SatelliteController mSatelliteController;
-    @Mock ExponentialBackoff mExponentialBackoff;
     private PersistableBundle mCarrierConfigBundle;
     private TestSatelliteEntitlementController mSatelliteEntitlementController;
     private Handler mHandler;
@@ -157,7 +172,8 @@
     }
 
     @Test
-    public void testIsQueryAvailable() throws Exception {
+    public void testShouldStartQueryEntitlement() throws Exception {
+        logd("testShouldStartQueryEntitlement");
         doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
 
         // Verify don't start the query when KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL is false.
@@ -171,19 +187,8 @@
 
         mCarrierConfigBundle.putBoolean(
                 CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
-        // Verify don't start the query when ExponentialBackoff is in progressed.
-        replaceInstance(SatelliteEntitlementController.class, "mExponentialBackoffPerSub",
-                mSatelliteEntitlementController, Map.of(SUB_ID, mExponentialBackoff));
-        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
-
-        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
-        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), anyList(), any());
-
-        replaceInstance(SatelliteEntitlementController.class, "mExponentialBackoffPerSub",
-                mSatelliteEntitlementController, new HashMap<>());
         // Verify don't start the query when Internet is disconnected.
-        doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+        clearInvocationsForMock();
         setInternetConnected(false);
         mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
 
@@ -200,8 +205,36 @@
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
                 anyBoolean(), anyList(), anyList(), any());
 
-        // Verify start the query when isQueryAvailable return true
         setLastQueryTime(0L);
+        // Verify don't start the query when retry count is reached max
+        setLastQueryTime(0L);
+        Map<Integer, Integer> mRetryCountPerSub = new HashMap<>();
+        mRetryCountPerSub.put(SUB_ID, MAX_RETRY_COUNT);
+        replaceInstance(SatelliteEntitlementController.class, "mRetryCountPerSub",
+                mSatelliteEntitlementController, mRetryCountPerSub);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        replaceInstance(SatelliteEntitlementController.class, "mRetryCountPerSub",
+                mSatelliteEntitlementController, new HashMap<>());
+
+        // Verify don't start the query when query is in progressed.
+        Map<Integer, Boolean> mIsEntitlementInProgressPerSub = new HashMap<>();
+        mIsEntitlementInProgressPerSub.put(SUB_ID, true);
+        replaceInstance(SatelliteEntitlementController.class, "mIsEntitlementInProgressPerSub",
+                mSatelliteEntitlementController, mIsEntitlementInProgressPerSub);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        replaceInstance(SatelliteEntitlementController.class, "mIsEntitlementInProgressPerSub",
+                mSatelliteEntitlementController, new HashMap<>());
+        // Verify the query starts when ShouldStartQueryEntitlement returns true.
         doReturn(mSatelliteEntitlementResult).when(
                 mSatelliteEntitlementApi).checkEntitlementStatus();
         setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
@@ -215,6 +248,7 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatus() throws Exception {
+        logd("testCheckSatelliteEntitlementStatus");
         setIsQueryAvailableTrue();
         // Verify don't call the checkSatelliteEntitlementStatus when getActiveSubIdList is empty.
         doReturn(new int[]{}).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
@@ -238,7 +272,7 @@
         // Verify call the updateSatelliteEntitlementStatus with satellite service is disabled
         // , empty PLMNAllowed and empty PLMNBarred.
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
-                eq(false), eq(new ArrayList<>()), eq(new ArrayList<>()), any());
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
 
         // Verify call the checkSatelliteEntitlementStatus with the subscribed result.
         clearInvocationsForMock();
@@ -276,7 +310,7 @@
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(PLMN_ALLOWED_LIST), eq(new ArrayList<>()), any());
+                eq(PLMN_ALLOWED_LIST), eq(EMPTY_PLMN_LIST), any());
 
         // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
         // empty PLMNAllowedList and PLMNBarredList.
@@ -288,7 +322,7 @@
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(new ArrayList<>()), eq(new ArrayList<>()), any());
+                eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
 
         // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
         // empty PLMNAllowedList and availablePLMNBarredList.
@@ -300,17 +334,14 @@
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(new ArrayList<>()), eq(PLMN_BARRED_LIST), any());
+                eq(EMPTY_PLMN_LIST), eq(PLMN_BARRED_LIST), any());
     }
 
     @Test
     public void testCheckSatelliteEntitlementStatusWhenInternetConnected() throws Exception {
-        Field fieldNetworkCallback = SatelliteEntitlementController.class.getDeclaredField(
-                "mNetworkCallback");
-        fieldNetworkCallback.setAccessible(true);
+        logd("testCheckSatelliteEntitlementStatusWhenInternetConnected");
         ConnectivityManager.NetworkCallback networkCallback =
-                (ConnectivityManager.NetworkCallback) fieldNetworkCallback.get(
-                        mSatelliteEntitlementController);
+                (ConnectivityManager.NetworkCallback) getValue("mNetworkCallback");
         Network mockNetwork = mock(Network.class);
 
         // Verify the called the checkSatelliteEntitlementStatus when Internet is connected.
@@ -330,6 +361,7 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatusWhenCarrierConfigChanged() throws Exception {
+        logd("testCheckSatelliteEntitlementStatusWhenCarrierConfigChanged");
         // Verify the called the checkSatelliteEntitlementStatus when CarrierConfigChanged
         // occurred and Internet is connected.
         setInternetConnected(true);
@@ -344,6 +376,440 @@
                 eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
     }
 
+    @Test
+    public void testCheckWhenStartCmdIsReceivedDuringRetry() throws Exception {
+        logd("testCheckWhenStartCmdIsReceivedDuringRetry");
+        // Verify that start cmd is ignored and retry is performed up to 5 times when start cmd
+        // occurs during retries.
+        setIsQueryAvailableTrue();
+        set503RetryAfterResponse();
+        Map<Integer, Integer> retryCountPerSub =
+                (Map<Integer, Integer>) getValue("mRetryCountPerSub");
+
+        // Verify that the first query.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
+        // Verify that the retry count is 0 after receiving a 503 with retry-after header in
+        // response.
+        assertTrue(retryCountPerSub.getOrDefault(SUB_ID, 0) == 0);
+
+        // Verify that the retry count is 1 for the second query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+
+        // Verify that the retry count is 2 for the third query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+
+        // Verify that start CMD is ignored during retries.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+
+        // Verify that the retry count is 3 for the forth query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(4)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 3);
+
+        // Verify that the retry count is 4 for the fifth query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+
+        // Verify that start CMD is ignored during retries.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+
+        // Verify that the retry count is 5 for the sixth query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(6)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify only called onSatelliteEntitlementStatusUpdated once.
+        verify(mSatelliteController, times(1)).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+
+        // Verify that the query is not restarted after reaching the maximum retry count even if
+        // a start cmd is received.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(6)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify that the query is not restarted after reaching the maximum retry count even if
+        // a start cmd is received.
+        sendMessage(CMD_RETRY_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(6)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+    }
+
+    @Test
+    public void testCheckAfterInternetConnectionChangedDuringRetry() throws Exception {
+        logd("testCheckAfterInternetConnectionChangedDuringRetry");
+        // Verify that the retry count is maintained even when internet connection is lost and
+        // connected during retries, and that up to 5 retries are performed.
+        setIsQueryAvailableTrue();
+        set503RetryAfterResponse();
+        Map<Integer, Integer> retryCountPerSub =
+                (Map<Integer, Integer>) getValue("mRetryCountPerSub");
+
+        // Verify that the first query.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
+        // Verify that the retry count is 0 after receiving a 503 with retry-after header in
+        // response.
+        assertTrue(retryCountPerSub.getOrDefault(SUB_ID, 0) == 0);
+
+        // Verify that the retry count is 1 for the second query when receiving a 503 with
+        // retry-after header in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+
+        // Verify that no query is executed and the retry count does not increase when internet
+        // connection is lost during the second retry.
+        setInternetConnected(false);
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+
+        // Verify that the query is started when internet connection is restored and that the
+        // retry count does not increase.
+        setInternetConnected(true);
+        logd("internet connected again");
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+
+        // Verify that the retry count is increases after received a 503 with retry-after header
+        // in response.
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(4)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 3);
+
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(6)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(7)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify that the query is not restarted after reaching the maximum retry count even if
+        // a start cmd is received.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(7)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify that the query is not restarted after reaching the maximum retry count even if
+        // a retry cmd is received.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(7)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify only called onSatelliteEntitlementStatusUpdated once.
+        verify(mSatelliteController, times(1)).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_error500() throws Exception {
+        logd("testStartQueryEntitlementStatus_error500");
+        setIsQueryAvailableTrue();
+        Map<Integer, Integer> retryCountPerSub =
+                (Map<Integer, Integer>) getValue("mRetryCountPerSub");
+        setErrorResponse(500);
+
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+        verify(mSatelliteController, times(1)).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_error503_retrySuccess() throws Exception {
+        logd("testStartQueryEntitlementStatus_error503_retrySuccess");
+        setIsQueryAvailableTrue();
+        set503RetryAfterResponse();
+        Map<Integer, Integer> retryCountPerSub =
+                (Map<Integer, Integer>) getValue("mRetryCountPerSub");
+
+        // Verify that the first query.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+
+        // Verify whether the query has been retried and verify called
+        // onSatelliteEntitlementStatusUpdated after receive a success case.
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_otherError_retrySuccess() throws Exception {
+        logd("testStartQueryEntitlementStatus_otherError_retrySuccess");
+        setIsQueryAvailableTrue();
+        Map<Integer, Integer> retryCountPerSub =
+                (Map<Integer, Integer>) getValue("mRetryCountPerSub");
+        Map<Integer, Boolean> isEntitlementInProgressPerSub =
+                (Map<Integer, Boolean>) getValue("mIsEntitlementInProgressPerSub");
+        Map<Integer, ExponentialBackoff> exponentialBackoffPerSub =
+                (Map<Integer, ExponentialBackoff>) getValue("mExponentialBackoffPerSub");
+        setErrorResponse(400);
+
+        // Verify start the exponentialBackoff.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
+        assertNull(retryCountPerSub.get(SUB_ID));
+        assertTrue(isEntitlementInProgressPerSub.get(SUB_ID));
+        assertNotNull(exponentialBackoffPerSub.get(SUB_ID));
+        // Verify don't call the onSatelliteEntitlementStatusUpdated.
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Verify the retry in progress.
+        sendMessage(CMD_RETRY_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        // Verify don't call the onSatelliteEntitlementStatusUpdated.
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Received the 200 response, Verify call the onSatelliteEntitlementStatusUpdated.
+        setIsQueryAvailableTrue();
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+
+        sendMessage(CMD_RETRY_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
+        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+    }
+
+    @Test
+    public void testSatelliteEntitlementSupportedChangedFromSupportToNotSupport() throws Exception {
+        logd("testSatelliteEntitlementSupportedChangedFromSupportToNotSupport");
+        setIsQueryAvailableTrue();
+
+        // KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL changed from Support(entitlement status
+        // disabled) to not support.
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_DISABLED, EMPTY_PLMN_LIST,
+                EMPTY_PLMN_LIST);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        // Verify call the onSatelliteEntitlementStatusUpdated - entitlement status false
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+
+        // Verify call the onSatelliteEntitlementStatusUpdated - entitlement status true
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
+                eq(true), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+
+        // KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL changed from Support(entitlement status
+        // enabled) to not support.
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        // Verify call the onSatelliteEntitlementStatusUpdated - entitlement status true.
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
+                eq(true), eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+
+        // Verify not call the onSatelliteEntitlementStatusUpdated.
+        clearInvocationsForMock();
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                eq(true), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_refreshStatus() throws Exception {
+        logd("testStartQueryEntitlementStatus_refreshStatus");
+        setIsQueryAvailableTrue();
+        mCarrierConfigBundle.putInt(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 1);
+
+        // Verify start query and success.
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // After move to the refresh time, verify the query started and success.
+        setLastQueryTime(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1) - 1000);
+        mTestableLooper.moveTimeForward(TimeUnit.DAYS.toMillis(1));
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        verify(mSatelliteController, times(2)).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_internetDisconnectedAndConnectedAgain()
+            throws Exception {
+        logd("testStartQueryEntitlementStatus_internetDisconnectedAndConnectedAgain");
+        setIsQueryAvailableTrue();
+
+        // Verify the query does not start if there is no internet connection.
+        setInternetConnected(false);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Verify the query start and success after internet connected.
+        setInternetConnected(true);
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_error503_error500() throws Exception {
+        logd("testStartQueryEntitlementStatus_error503_error500");
+        setIsQueryAvailableTrue();
+        set503RetryAfterResponse();
+
+        // Verify that the first query was triggered and that onSatelliteEntitlementStatusUpdated
+        // was not called after received a 503 error.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Verify whether the second query has been triggered and whether
+        // onSatelliteEntitlementStatusUpdated has been called after received the 500 error.
+        reset(mSatelliteEntitlementApi);
+        setErrorResponse(500);
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
+                eq(false), eq(EMPTY_PLMN_LIST), eq(EMPTY_PLMN_LIST), any());
+    }
+
+    @Test
+    public void testStartQueryEntitlementStatus_error503_otherError() throws Exception {
+        logd("testStartQueryEntitlementStatus_error503_otherError");
+        setIsQueryAvailableTrue();
+        set503RetryAfterResponse();
+
+        // Verify that the first query was triggered and that onSatelliteEntitlementStatusUpdated
+        // was not called after received a 503 error.
+        sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Verify whether the second query was triggered and onSatelliteEntitlementStatusUpdated
+        // was not called after received a 503 error without valid retry-after header.
+        reset(mSatelliteEntitlementApi);
+        setErrorResponse(503);
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.processAllMessages();
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), anyList(), any());
+
+        // Verify whether the third query was triggered and onSatelliteEntitlementStatusUpdated
+        // was called after received a success case.
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
+        mTestableLooper.moveTimeForward(TimeUnit.MINUTES.toMillis(10));
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+    }
+
     private void triggerCarrierConfigChanged() {
         for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
                 : mCarrierConfigChangedListenerList) {
@@ -354,6 +820,16 @@
         mTestableLooper.processAllMessages();
     }
 
+    private void triggerCarrierConfigChanged(int subId) {
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ subId, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        mTestableLooper.processAllMessages();
+    }
+
     private void clearInvocationsForMock() {
         clearInvocations(mSatelliteEntitlementApi);
         clearInvocations(mSatelliteController);
@@ -365,11 +841,15 @@
                 CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
         replaceInstance(SatelliteEntitlementController.class, "mRetryCountPerSub",
                 mSatelliteEntitlementController, new HashMap<>());
+        replaceInstance(SatelliteEntitlementController.class, "mIsEntitlementInProgressPerSub",
+                mSatelliteEntitlementController, new HashMap<>());
         setInternetConnected(true);
         setLastQueryTime(0L);
         replaceInstance(SatelliteEntitlementController.class,
                 "mSatelliteEntitlementResultPerSub", mSatelliteEntitlementController,
                 new HashMap<>());
+        replaceInstance(SatelliteEntitlementController.class,
+                "mSubIdPerSlot", mSatelliteEntitlementController, new HashMap<>());
     }
 
     private void setInternetConnected(boolean connected) {
@@ -398,6 +878,41 @@
         lastQueryTimePerSub.put(SUB_ID, lastQueryTime);
     }
 
+    private void set503RetryAfterResponse() throws Exception {
+        when(mSatelliteEntitlementApi.checkEntitlementStatus()).thenAnswer(
+                new Answer() {
+                    @Override
+                    public Object answer(InvocationOnMock invocation) throws Throwable {
+                        throw new ServiceEntitlementException(
+                                ERROR_HTTP_STATUS_NOT_SUCCESS, 503, "1", "503 occurred");
+                    }
+                }
+        );
+    }
+
+    private void setErrorResponse(int errorCode) throws Exception {
+        when(mSatelliteEntitlementApi.checkEntitlementStatus()).thenAnswer(
+                new Answer() {
+                    @Override
+                    public Object answer(InvocationOnMock invocation) throws Throwable {
+                        throw new ServiceEntitlementException(
+                                ERROR_HTTP_STATUS_NOT_SUCCESS, errorCode, "",
+                                errorCode + " occurred");
+                    }
+                }
+        );
+    }
+
+    private void sendMessage(int what, int subId) {
+        mSatelliteEntitlementController.handleMessage(mHandler.obtainMessage(what, subId, 0));
+    }
+
+    private Object getValue(String originalObjectName) throws Exception {
+        Field field = SatelliteEntitlementController.class.getDeclaredField(originalObjectName);
+        field.setAccessible(true);
+        return field.get(mSatelliteEntitlementController);
+    }
+
     public static class TestSatelliteEntitlementController extends SatelliteEntitlementController {
         private SatelliteEntitlementApi mInjectSatelliteEntitlementApi;
 
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 53f3b8a..a496bd1 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -2928,6 +2928,68 @@
     }
 
     @Test
+    public void testDefaultLimitedServiceEutranFailScanLimitedOnly() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL,
+                true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt(), anyVararg())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(EUTRAN,
+                REGISTRATION_STATE_UNKNOWN,
+                0, false, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        processAllMessages();
+        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS), eq(true));
+
+        attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, false, regResult,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, 0, null));
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        // Verify CS preferred limited service only scan
+        verify(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE),
+                anyBoolean(), any(), any());
+        assertEquals(UTRAN, (int) mAccessNetwork.get(0));
+    }
+
+    @Test
+    public void testDefaultLimitedServiceEutranFailPinLocked() throws Exception {
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManager).getSimState(anyInt());
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(EUTRAN,
+                REGISTRATION_STATE_UNKNOWN,
+                0, false, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        processAllMessages();
+        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS), eq(true));
+
+        attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, false, regResult,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, 0, null));
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verifyScanCsPreferred();
+    }
+
+    @Test
     public void testDefaultLimitedServiceScanTypeFullService() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_FULL_SERVICE);