Merge "Update code to avoid nested usage of locks." into main
diff --git a/Android.bp b/Android.bp
index da32208..a6e526c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -82,14 +82,14 @@
         "android.hardware.radio-V1.4-java",
         "android.hardware.radio-V1.5-java",
         "android.hardware.radio-V1.6-java",
-        "android.hardware.radio.config-V3-java",
-        "android.hardware.radio.data-V3-java",
-        "android.hardware.radio.ims-V2-java",
-        "android.hardware.radio.messaging-V3-java",
-        "android.hardware.radio.modem-V3-java",
-        "android.hardware.radio.network-V3-java",
-        "android.hardware.radio.sim-V3-java",
-        "android.hardware.radio.voice-V3-java",
+        "android.hardware.radio.config-V4-java",
+        "android.hardware.radio.data-V4-java",
+        "android.hardware.radio.ims-V3-java",
+        "android.hardware.radio.messaging-V4-java",
+        "android.hardware.radio.modem-V4-java",
+        "android.hardware.radio.network-V4-java",
+        "android.hardware.radio.sim-V4-java",
+        "android.hardware.radio.voice-V4-java",
         "voip-common",
         "ims-common",
         "unsupportedappusage",
diff --git a/flags/carrier.aconfig b/flags/carrier.aconfig
index 265d258..14aedc6 100644
--- a/flags/carrier.aconfig
+++ b/flags/carrier.aconfig
@@ -21,3 +21,12 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+# OWNER=melhuishj TARGET=25Q2
+flag {
+    name: "temporary_failures_in_carrier_messaging_service"
+    is_exported: true
+    namespace: "telephony"
+    description: "Enable temporary failures in CarrierMessagingService"
+    bug:"326610112"
+}
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index 871cabc..b209d1d 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -825,6 +825,9 @@
 
         SmsResponse smsResponse = new SmsResponse(messageRef, null /* ackPdu */, NO_ERROR_CODE,
                 tracker.mMessageId);
+        if (Flags.temporaryFailuresInCarrierMessagingService()) {
+            tracker.mResultCodeFromCarrierMessagingService = result;
+        }
 
         switch (result) {
             case CarrierMessagingService.SEND_STATUS_OK:
@@ -836,10 +839,34 @@
                                                           smsResponse,
                                                           null /* exception*/)));
                 break;
-            case CarrierMessagingService.SEND_STATUS_ERROR:
-                Rlog.d(TAG, "processSendSmsResponse: Sending SMS by CarrierMessagingService"
-                        + " failed. "
-                        + SmsController.formatCrossStackMessageId(tracker.mMessageId));
+            case CarrierMessagingService.SEND_STATUS_ERROR: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_NULL_PDU: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_NO_SERVICE: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE: // fall through
+            case CarrierMessagingService
+                    .SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED: // fall through
+            case CarrierMessagingService
+                    .SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_NETWORK_REJECT: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_ARGUMENTS: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_STATE: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_SMS_FORMAT: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_NETWORK_ERROR: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_ENCODING_ERROR: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_CANCELLED: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED: // fall through
+            case CarrierMessagingService
+                    .SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY: // fall through
+            case CarrierMessagingService.SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED: // fall through
+                Rlog.d(
+                        TAG,
+                        "processSendSmsResponse: Sending SMS by CarrierMessagingService"
+                                + " failed. "
+                                + SmsController.formatCrossStackMessageId(tracker.mMessageId));
                 sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
                         new AsyncResult(tracker, smsResponse,
                                 new CommandException(CommandException.Error.GENERIC_FAILURE))));
@@ -858,6 +885,55 @@
         }
     }
 
+    private int toSmsManagerResultForSendSms(int carrierMessagingServiceResult) {
+        switch (carrierMessagingServiceResult) {
+            case CarrierMessagingService.SEND_STATUS_OK:
+                return Activity.RESULT_OK;
+            case CarrierMessagingService.SEND_STATUS_ERROR:
+                return SmsManager.RESULT_RIL_GENERIC_ERROR;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE:
+                return SmsManager.RESULT_ERROR_GENERIC_FAILURE;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_NULL_PDU:
+                return SmsManager.RESULT_ERROR_NULL_PDU;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_NO_SERVICE:
+                return SmsManager.RESULT_ERROR_NO_SERVICE;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED:
+                return SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE:
+                return SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED:
+                return SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED:
+                return SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_NETWORK_REJECT:
+                return SmsManager.RESULT_NETWORK_REJECT;
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_ARGUMENTS:
+                return SmsManager.RESULT_INVALID_ARGUMENTS;
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_STATE:
+                return SmsManager.RESULT_INVALID_STATE;
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_SMS_FORMAT:
+                return SmsManager.RESULT_INVALID_SMS_FORMAT;
+            case CarrierMessagingService.SEND_STATUS_RESULT_NETWORK_ERROR:
+                return SmsManager.RESULT_NETWORK_ERROR;
+            case CarrierMessagingService.SEND_STATUS_RESULT_ENCODING_ERROR:
+                return SmsManager.RESULT_ENCODING_ERROR;
+            case CarrierMessagingService.SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS:
+                return SmsManager.RESULT_INVALID_SMSC_ADDRESS;
+            case CarrierMessagingService.SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED:
+                return SmsManager.RESULT_OPERATION_NOT_ALLOWED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_CANCELLED:
+                return SmsManager.RESULT_CANCELLED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED:
+                return SmsManager.RESULT_REQUEST_NOT_SUPPORTED;
+            case CarrierMessagingService.SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY:
+                return SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY;
+            case CarrierMessagingService.SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED:
+                return SmsManager.RESULT_SMS_SEND_RETRY_FAILED;
+            default:
+                return SmsManager.RESULT_ERROR_GENERIC_FAILURE;
+        }
+    }
+
     /**
      * Use the carrier messaging service to send a multipart text SMS.
      */
@@ -1084,10 +1160,20 @@
                         + SmsController.formatCrossStackMessageId(tracker.mMessageId));
             }
 
-            int ss = mPhone.getServiceState().getState();
-            int error = rilErrorToSmsManagerResult(
-                    ((CommandException) (ar.exception)).getCommandError(), tracker);
+            int error;
+            if (Flags.temporaryFailuresInCarrierMessagingService()
+                    && tracker.mResultCodeFromCarrierMessagingService
+                            != CarrierMessagingService.SEND_STATUS_OK) {
+                error =
+                        toSmsManagerResultForSendSms(
+                                tracker.mResultCodeFromCarrierMessagingService);
+            } else {
+                error =
+                        rilErrorToSmsManagerResult(
+                                ((CommandException) (ar.exception)).getCommandError(), tracker);
+            }
 
+            int ss = mPhone.getServiceState().getState();
             if (tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
                 // This is retry after failure over IMS but voice is not available.
                 // Set retry to max allowed, so no retry is sent and cause
@@ -2489,6 +2575,9 @@
 
         public final long mMessageId;
 
+        // A CarrierMessagingService result code to be returned to the caller.
+        public int mResultCodeFromCarrierMessagingService;
+
         private Boolean mIsFromDefaultSmsApplication;
 
         private int mCarrierId;
@@ -2533,6 +2622,7 @@
             mCarrierId = carrierId;
             mSkipShortCodeDestAddrCheck = skipShortCodeDestAddrCheck;
             mUniqueMessageId = uniqueMessageId;
+            mResultCodeFromCarrierMessagingService = CarrierMessagingService.SEND_STATUS_OK;
         }
 
         @VisibleForTesting
@@ -2552,6 +2642,7 @@
             mCarrierId = 0;
             mSkipShortCodeDestAddrCheck = false;
             mUniqueMessageId = 0;
+            mResultCodeFromCarrierMessagingService = CarrierMessagingService.SEND_STATUS_OK;
         }
 
         public HashMap<String, Object> getData() {
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 48cc7cb..b3e8095 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -109,8 +109,6 @@
      * from the modem.
      */
     private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1 * 1000;
-    @VisibleForTesting
-    public static final int DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS = 3 * 1000;
     /** Default value for if Emergency Callback Mode is supported. */
     private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true;
     /** Default Emergency Callback Mode exit timeout value. */
@@ -142,6 +140,7 @@
     private final CarrierConfigManager mConfigManager;
     private final Handler mHandler;
     private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall;
+    private final int mWaitForInServiceTimeoutMs;
     private final PowerManager.WakeLock mWakeLock;
     private RadioOnHelper mRadioOnHelper;
     @EmergencyConstants.EmergencyMode
@@ -474,10 +473,10 @@
      * @param featureFlags                            The telephony feature flags.
      */
     public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall,
-            @NonNull FeatureFlags featureFlags) {
+            int waitForInServiceTimeout, @NonNull FeatureFlags featureFlags) {
         if (INSTANCE == null) {
             INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(),
-                    isSuplDdsSwitchRequiredForEmergencyCall, featureFlags);
+                    isSuplDdsSwitchRequiredForEmergencyCall, waitForInServiceTimeout, featureFlags);
         }
     }
 
@@ -497,11 +496,13 @@
      * Initializes EmergencyStateTracker.
      */
     private EmergencyStateTracker(Context context, Looper looper,
-            boolean isSuplDdsSwitchRequiredForEmergencyCall, @NonNull FeatureFlags featureFlags) {
+            boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout,
+            @NonNull FeatureFlags featureFlags) {
         mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS;
         mContext = context;
         mHandler = new MyHandler(looper);
         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
+        mWaitForInServiceTimeoutMs = waitForInServiceTimeout;
         mFeatureFlags = featureFlags;
         PowerManager pm = context.getSystemService(PowerManager.class);
         mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -534,6 +535,10 @@
      * @param looper                                  The {@link Looper} of the application.
      * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for
      *                                                emergency call.
+     * @param waitForInServiceTimeout                 The timeout duration how long does it wait for
+     *                                                modem to get in-service state when emergency
+     *                                                call is dialed in airplane mode before
+     *                                                starting the emergency call.
      * @param phoneFactoryProxy                       The {@link PhoneFactoryProxy} to be injected.
      * @param phoneSwitcherProxy                      The {@link PhoneSwitcherProxy} to be injected.
      * @param telephonyManagerProxy                   The {@link TelephonyManagerProxy} to be
@@ -543,12 +548,14 @@
      */
     @VisibleForTesting
     public EmergencyStateTracker(Context context, Looper looper,
-            boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy,
-            PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy,
-            RadioOnHelper radioOnHelper, long ecmExitTimeoutMs, FeatureFlags featureFlags) {
+            boolean isSuplDdsSwitchRequiredForEmergencyCall, int waitForInServiceTimeout,
+            PhoneFactoryProxy phoneFactoryProxy, PhoneSwitcherProxy phoneSwitcherProxy,
+            TelephonyManagerProxy telephonyManagerProxy, RadioOnHelper radioOnHelper,
+            long ecmExitTimeoutMs, FeatureFlags featureFlags) {
         mContext = context;
         mHandler = new MyHandler(looper);
         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
+        mWaitForInServiceTimeoutMs = waitForInServiceTimeout;
         mPhoneFactoryProxy = phoneFactoryProxy;
         mPhoneSwitcherProxy = phoneSwitcherProxy;
         mTelephonyManagerProxy = telephonyManagerProxy;
@@ -1689,8 +1696,7 @@
 
             final Phone phoneForEmergency = phone;
             final android.telecom.Connection expectedConnection = mOngoingConnection;
-            final int waitForInServiceTimeout =
-                    needToTurnOnRadio ? DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS : 0;
+            final int waitForInServiceTimeout = needToTurnOnRadio ? mWaitForInServiceTimeoutMs : 0;
             Rlog.i(TAG, "turnOnRadioAndSwitchDds: timeout=" + waitForInServiceTimeout);
             mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() {
                 @Override
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 1f6ca19..762649a 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -30,6 +30,7 @@
 import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
@@ -55,6 +56,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
@@ -140,6 +142,7 @@
 import android.telephony.satellite.SatelliteSubscriberInfo;
 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.telephony.satellite.SatelliteSubscriptionInfo;
+import android.telephony.satellite.SystemSelectionSpecifier;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -190,6 +193,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
+import com.android.internal.R;
 
 /**
  * Satellite controller is the backend service of
@@ -298,6 +302,8 @@
     private static final int EVENT_TERRESTRIAL_NETWORK_AVAILABLE_CHANGED = 55;
     private static final int EVENT_SET_NETWORK_SELECTION_AUTO_DONE = 56;
     private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 57;
+    private static final int CMD_UPDATE_SYSTEM_SELECTION_CHANNELS = 58;
+    private static final int EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE = 59;
 
     @NonNull private static SatelliteController sInstance;
     @NonNull private final Context mContext;
@@ -480,6 +486,13 @@
      * {@code true} for enabled and {@code false} for disabled. */
     @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub =
             new HashMap<>();
+    /** Key: subId, value: (key: Regional satellite config Id string, value: Integer
+     * arrays of earfcns in the corresponding regions.)
+     */
+    @GuardedBy("mRegionalSatelliteEarfcnsLock")
+    @NonNull private final Map<Integer, Map<String, Set<Integer>>>
+            mRegionalSatelliteEarfcns = new HashMap<>();
+    @NonNull private final Object mRegionalSatelliteEarfcnsLock = new Object();
     @NonNull private final FeatureFlags mFeatureFlags;
     @NonNull private final Object mSatelliteConnectedLock = new Object();
     /** Key: Subscription ID; Value: Last satellite connected time */
@@ -1217,6 +1230,17 @@
         }
     }
 
+    private static final class UpdateSystemSelectionChannelsArgument {
+        @NonNull SystemSelectionSpecifier mSelectionSpecifier;
+        @NonNull ResultReceiver mResult;
+
+        UpdateSystemSelectionChannelsArgument(@NonNull SystemSelectionSpecifier selectionSpecifier,
+                @NonNull ResultReceiver result) {
+            this.mSelectionSpecifier = selectionSpecifier;
+            this.mResult = result;
+        }
+    }
+
     /**
      * Arguments to send to SatelliteTransmissionUpdate registrants
      */
@@ -2035,6 +2059,29 @@
                 int phoneId = (int) ar.userObj;
                 updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(
                         PhoneFactory.getPhone(phoneId));
+                break;
+            }
+
+            case CMD_UPDATE_SYSTEM_SELECTION_CHANNELS: {
+                plogd("CMD_UPDATE_SYSTEM_SELECTION_CHANNELS");
+                request = (SatelliteControllerHandlerRequest) msg.obj;
+                onCompleted = obtainMessage(EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE, request);
+                mSatelliteModemInterface.updateSystemSelectionChannels(
+                        ((UpdateSystemSelectionChannelsArgument) (request.argument))
+                                .mSelectionSpecifier,
+                        onCompleted);
+                break;
+            }
+
+            case EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE: {
+                ar = (AsyncResult) msg.obj;
+                request = (SatelliteControllerHandlerRequest) ar.userObj;
+                int error =  SatelliteServiceUtils.getSatelliteError(
+                        ar, "updateSystemSelectionChannel");
+                plogd("EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE = " + error);
+                ((UpdateSystemSelectionChannelsArgument) (request.argument)).mResult.send(error,
+                        null);
+                break;
             }
 
             default:
@@ -4567,14 +4614,31 @@
         boolean provisionChanged = false;
         synchronized (mSatelliteTokenProvisionedLock) {
             for (SatelliteSubscriberInfo subscriberInfo : newList) {
+
+                int subId = subscriberInfo.getSubId();
                 Boolean currentProvisioned =
                         mProvisionedSubscriberId.get(subscriberInfo.getSubscriberId());
-                if (currentProvisioned != null && currentProvisioned == provisioned) {
+                if (currentProvisioned == null) {
+                    currentProvisioned = false;
+                }
+
+                Boolean isProvisionedInPersistentDb = false;
+                try {
+                    isProvisionedInPersistentDb = mSubscriptionManagerService
+                         .isSatelliteProvisionedForNonIpDatagram(subId);
+                    if (isProvisionedInPersistentDb == null) {
+                        isProvisionedInPersistentDb = false;
+                    }
+                } catch (IllegalArgumentException | SecurityException ex) {
+                    ploge("isSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex="
+                            + ex);
+                }
+                if (currentProvisioned == provisioned
+                        && isProvisionedInPersistentDb == provisioned) {
                     continue;
                 }
                 provisionChanged = true;
                 mProvisionedSubscriberId.put(subscriberInfo.getSubscriberId(), provisioned);
-                int subId = subscriberInfo.getSubId();
                 try {
                     mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId,
                             provisioned);
@@ -5168,6 +5232,13 @@
                         KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
     }
 
+    @NonNull
+    private Map<String, Set<Integer>> readRegionalSatelliteEarfcnsFromCarrierConfig(int subId) {
+        PersistableBundle config = getPersistableBundle(subId);
+        return SatelliteServiceUtils.parseRegionalSatelliteEarfcns(
+                config.getPersistableBundle(KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE));
+    }
+
     @NonNull private PersistableBundle getConfigForSubId(int subId) {
         PersistableBundle config = null;
         if (mCarrierConfigManager != null) {
@@ -5191,7 +5262,8 @@
                         KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT,
                         KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT,
                         KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE,
-                        KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY
+                        KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY,
+                        KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE
                 );
             } catch (Exception e) {
                 logw("getConfigForSubId: " + e);
@@ -5222,6 +5294,7 @@
         evaluateCarrierRoamingNtnEligibilityChange();
         sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
                 mEvaluateEsosProfilesPrioritizationDurationMillis);
+        updateRegionalSatelliteEarfcns(subId);
     }
 
     // imsi, msisdn, default sms subId change
@@ -6313,6 +6386,13 @@
      */
     private void updateSatelliteSystemNotification(int subId,
             @CARRIER_ROAMING_NTN_CONNECT_TYPE int carrierRoamingNtnConnectType, boolean visible) {
+        boolean notifySatelliteAvailabilityEnabled =
+            mContext.getResources().getBoolean(R.bool.config_satellite_should_notify_availability);
+        if (!mFeatureFlags.carrierRoamingNbIotNtn() || !notifySatelliteAvailabilityEnabled) {
+            plogd("updateSatelliteSystemNotification: satellite notifications are not enabled.");
+            return;
+        }
+
         plogd("updateSatelliteSystemNotification subId=" + subId + ", carrierRoamingNtnConnectType="
                 + SatelliteServiceUtils.carrierRoamingNtnConnectTypeToString(
                 carrierRoamingNtnConnectType) + ", visible=" + visible);
@@ -7041,6 +7121,34 @@
         }
     }
 
+    /**
+     * Request to get the currently selected satellite subscription id.
+     *
+     * @param result The result receiver that returns the currently selected satellite subscription
+     *               id if the request is successful or an error code if the request failed.
+     */
+    public void requestSelectedNbIotSatelliteSubscriptionId(@NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            logd("requestSelectedNbIotSatelliteSubscriptionId: carrierRoamingNbIotNtn is disabled");
+            return;
+        }
+
+        int selectedSatelliteSubId = getSelectedSatelliteSubId();
+        plogd("requestSelectedNbIotSatelliteSubscriptionId: " + selectedSatelliteSubId);
+        if (selectedSatelliteSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            result.send(SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION, null);
+            logd("requestSelectedNbIotSatelliteSubscriptionId: "
+                    + "selectedSatelliteSubId is invalid");
+            return;
+        }
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(SatelliteManager.KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID,
+                selectedSatelliteSubId);
+        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+    }
+
     private void selectBindingSatelliteSubscription(boolean shouldIgnoreEnabledState) {
         if ((isSatelliteEnabled() || isSatelliteBeingEnabled()) && !shouldIgnoreEnabledState) {
             plogd("selectBindingSatelliteSubscription: satellite subscription will be selected "
@@ -7136,6 +7244,63 @@
     }
 
     /**
+     * Request to update system selection channels.
+     *
+     * @param result The result receiver that returns if the request is successful or
+     *               an error code if the request failed.
+     */
+    public void updateSystemSelectionChannels(@NonNull SystemSelectionSpecifier selectionSpecifier,
+            @NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            plogd("updateSystemSelectionChannels: "
+                    + "carrierRoamingNbIotNtn flag is disabled");
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            return;
+        }
+
+        sendRequestAsync(CMD_UPDATE_SYSTEM_SELECTION_CHANNELS,
+                new UpdateSystemSelectionChannelsArgument(selectionSpecifier, result), null);
+    }
+
+    /**
+     * @param subId Subscription ID.
+     * @return The The map of earfcns with key: regional satellite config Id,
+     * value: set of earfcns in the corresponding regions associated with the {@code subId}.
+     */
+    @NonNull
+    public Map<String, Set<Integer>> getRegionalSatelliteEarfcns(int subId) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            logd("getRegionalSatelliteEarfcns: carrierRoamingNbIotNtnFlag is disabled");
+            return new HashMap<>();
+        }
+        synchronized (mRegionalSatelliteEarfcnsLock) {
+            if (mRegionalSatelliteEarfcns.containsKey(subId)) {
+                return mRegionalSatelliteEarfcns.get(subId);
+            } else {
+                logd("getRegionalSatelliteEarfcns: Earfcns for subId: " + subId + " not found");
+                return new HashMap<>();
+            }
+        }
+    }
+
+    /**
+     * Update regional satellite earfcn information from carrier config.
+     */
+    public void updateRegionalSatelliteEarfcns(int subId) {
+        plogd("updateRegionalSatelliteEarfcns with subId " + subId);
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            plogd("updateRegionalSatelliteEarfcns: "
+                    + "carrierRoamingNbIotNtn flag is disabled");
+            return;
+        }
+
+        synchronized (mRegionalSatelliteEarfcnsLock) {
+            mRegionalSatelliteEarfcns.put(subId,
+                    readRegionalSatelliteEarfcnsFromCarrierConfig(subId));
+        }
+    }
+
+    /**
      * Deliver the list of deprovisioned satellite subscriber ids.
      *
      * @param list List of deprovisioned satellite subscriber ids.
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 5fa85db..6f88f59 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -41,6 +41,7 @@
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteManager.SatelliteException;
 import android.telephony.satellite.SatelliteModemEnableRequestAttributes;
+import android.telephony.satellite.SystemSelectionSpecifier;
 import android.telephony.satellite.stub.INtnSignalStrengthConsumer;
 import android.telephony.satellite.stub.ISatellite;
 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
@@ -1383,6 +1384,42 @@
         mExponentialBackoff.start();
     }
 
+    /**
+     * Request to update system selection channels
+     *
+     * @param systemSelectionSpecifier system selection specifiers
+     * @param message The Message to send to result of the operation to.
+     */
+    public void updateSystemSelectionChannels(
+            @NonNull SystemSelectionSpecifier systemSelectionSpecifier,
+            @Nullable Message message) {
+        plogd("updateSystemSelectionChannels: SystemSelectionSpecifier: "
+                + systemSelectionSpecifier.toString());
+        if (mSatelliteService != null) {
+            try {
+                mSatelliteService.updateSystemSelectionChannels(SatelliteServiceUtils
+                                .toSystemSelectionSpecifier(systemSelectionSpecifier),
+                        new IIntegerConsumer.Stub() {
+                            @Override
+                            public void accept(int result) {
+                                int error = SatelliteServiceUtils.fromSatelliteError(result);
+                                plogd("updateSystemSelectionChannels: " + error);
+                                Binder.withCleanCallingIdentity(() ->
+                                        sendMessageWithResult(message, null, error));
+                            }
+                        });
+            } catch (RemoteException e) {
+                ploge("updateSystemSelectionChannels: RemoteException " + e);
+                sendMessageWithResult(message, null,
+                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+            }
+        } else {
+            ploge("updateSystemSelectionChannels: Satellite service is unavailable.");
+            sendMessageWithResult(message, null,
+                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
+        }
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result,
             @SatelliteManager.SatelliteResult int error) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index 3936a7e..9217ba1 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -43,6 +43,7 @@
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteModemEnableRequestAttributes;
 import android.telephony.satellite.SatelliteSubscriptionInfo;
+import android.telephony.satellite.SystemSelectionSpecifier;
 import android.telephony.satellite.stub.NTRadioTechnology;
 import android.telephony.satellite.stub.SatelliteModemState;
 import android.telephony.satellite.stub.SatelliteResult;
@@ -53,6 +54,7 @@
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.TelephonyUtils;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -542,6 +544,56 @@
         return mcc + mnc;
     }
 
+    /**
+     * Convert SystemSelectionSpecifier from framework definition to service definition
+     * @param systemSelectionSpecifier The SystemSelectionSpecifier from the framework.
+     * @return The converted SystemSelectionSpecifier for the satellite service.
+     */
+    @NonNull public static List<android.telephony.satellite.stub
+            .SystemSelectionSpecifier> toSystemSelectionSpecifier(
+            @NonNull SystemSelectionSpecifier systemSelectionSpecifier) {
+        List<android.telephony.satellite.stub.SystemSelectionSpecifier> converted =
+                new ArrayList<>();
+        android.telephony.satellite.stub.SystemSelectionSpecifier convertedSpecifier =
+                new android.telephony.satellite.stub.SystemSelectionSpecifier();
+
+        convertedSpecifier.mMccMnc = systemSelectionSpecifier.getMccMnc();
+        convertedSpecifier.mBands = systemSelectionSpecifier.getBands().toArray();
+        convertedSpecifier.mEarfcs = systemSelectionSpecifier.getEarfcs().toArray();
+        converted.add(convertedSpecifier);
+        return converted;
+    }
+
+    /**
+     * Expected format of the input dictionary bundle is:
+     * <ul>
+     *     <li>Key: Regional satellite config Id string.</li>
+     *     <li>Value: Integer arrays of earfcns in the corresponding regions."</li>
+     * </ul>
+     * @return The map of earfcns with key: regional satellite config Id,
+     * value: set of earfcns in the corresponding regions.
+     */
+    @NonNull
+    public static Map<String, Set<Integer>> parseRegionalSatelliteEarfcns(
+            @Nullable PersistableBundle earfcnsBundle) {
+        Map<String, Set<Integer>> earfcnsMap = new HashMap<>();
+        if (earfcnsBundle == null || earfcnsBundle.isEmpty()) {
+            logd("parseRegionalSatelliteEarfcns: earfcnsBundle is null or empty");
+            return earfcnsMap;
+        }
+
+        for (String configId : earfcnsBundle.keySet()) {
+            Set<Integer> earfcnsSet = new HashSet<>();
+            for (int earfcn : earfcnsBundle.getIntArray(configId)) {
+                earfcnsSet.add(earfcn);
+            }
+            logd("parseRegionalSatelliteEarfcns: configId = " + configId + ", earfcns ="
+                    + earfcnsSet.stream().map(String::valueOf).collect(joining(",")));
+            earfcnsMap.put(configId, earfcnsSet);
+        }
+        return earfcnsMap;
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index df14080..9253fbf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -27,7 +27,6 @@
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK;
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN;
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN;
-import static com.android.internal.telephony.emergency.EmergencyStateTracker.DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -106,6 +105,7 @@
     private static final String TEST_SMS_ID = "1111";
     private static final String TEST_SMS_ID_2 = "2222";
     private static final int TEST_ECM_EXIT_TIMEOUT_MS = 500;
+    private static final int TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS = 3000;
     private static final EmergencyRegistrationResult E_REG_RESULT = new EmergencyRegistrationResult(
             EUTRAN, REGISTRATION_STATE_HOME, DOMAIN_CS_PS, true, true, 0, 1, "001", "01", "US");
 
@@ -139,7 +139,8 @@
             EmergencyStateTracker.getInstance();
         });
 
-        EmergencyStateTracker.make(mContext, true, mFeatureFlags);
+        EmergencyStateTracker
+                .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags);
 
         assertNotNull(EmergencyStateTracker.getInstance());
     }
@@ -147,7 +148,8 @@
     @Test
     @SmallTest
     public void getInstance_returnsSameInstance() {
-        EmergencyStateTracker.make(mContext, true, mFeatureFlags);
+        EmergencyStateTracker
+                .make(mContext, true, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS, mFeatureFlags);
         EmergencyStateTracker instance1 = EmergencyStateTracker.getInstance();
         EmergencyStateTracker instance2 = EmergencyStateTracker.getInstance();
 
@@ -184,7 +186,7 @@
         ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                 .forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
-                eq(false), eq(DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
+                eq(false), eq(TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
         // isOkToCall() should return true when IN_SERVICE state
         assertFalse(callback.getValue()
                 .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
@@ -243,7 +245,7 @@
         ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                 .forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
-                eq(false), eq(DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
+                eq(false), eq(TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
         // onTimeout should return true when radion on
         assertFalse(callback.getValue()
                 .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
@@ -292,7 +294,7 @@
         ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                 .forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
-                eq(false), eq(DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
+                eq(false), eq(TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
 
         // Hangup the call
         testConnection.setDisconnected(null);
@@ -330,7 +332,7 @@
         ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                 .forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
-                eq(false), eq(DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
+                eq(false), eq(TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
         // Verify future completes with DisconnectCause.POWER_OFF if radio not ready
         CompletableFuture<Void> unused = future.thenAccept((result) -> {
             assertEquals((Integer) result, (Integer) DisconnectCause.POWER_OFF);
@@ -3411,8 +3413,9 @@
         doNothing().when(mPhoneSwitcher).overrideDefaultDataForEmergency(
                 anyInt(), anyInt(), any());
         return new EmergencyStateTracker(mContext, mTestableLooper.getLooper(),
-                isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy,
-                mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS, mFeatureFlags);
+                isSuplDdsSwitchRequiredForEmergencyCall, TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS,
+                mPhoneFactoryProxy, mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper,
+                TEST_ECM_EXIT_TIMEOUT_MS, mFeatureFlags);
     }
 
     private Phone setupTestPhoneForEmergencyCall(boolean isRoaming, boolean isRadioOn) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index 639a2a3..a29de0f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -70,6 +70,7 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TelephonyTestUtils;
 import com.android.internal.telephony.TestApplication;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.IsimUiccRecords;
 
@@ -377,23 +378,35 @@
                 any(ICarrierMessagingCallback.class));
     }
 
-    @Test
-    @SmallTest
-    @Ignore("b/256282780")
-    public void testSendSmsByCarrierApp() throws Exception {
+    private int sendSmsWithCarrierAppResponse(int carrierAppResultCode) throws Exception {
         mockCarrierApp();
-        mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK,
-                mICarrierAppMessagingService, true);
+        mockCarrierAppStubResults(carrierAppResultCode, mICarrierAppMessagingService, true);
         registerTestIntentReceiver();
 
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0,
-                new Intent(TEST_INTENT)
-                        .setPackage(TestApplication.getAppContext().getPackageName()),
-                PendingIntent.FLAG_MUTABLE);
+        PendingIntent pendingIntent =
+                PendingIntent.getBroadcast(
+                        TestApplication.getAppContext(),
+                        0,
+                        new Intent(TEST_INTENT)
+                                .setPackage(TestApplication.getAppContext().getPackageName()),
+                        PendingIntent.FLAG_MUTABLE);
         mReceivedTestIntent = false;
 
-        mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
-                pendingIntent, null, null, null, mCallingUserId, false, -1, false, -1, false, 0L);
+        mGsmSmsDispatcher.sendText(
+                "6501002000",
+                "121" /*scAddr*/,
+                "test sms",
+                pendingIntent,
+                null,
+                null,
+                null,
+                mCallingUserId,
+                false,
+                -1,
+                false,
+                -1,
+                false,
+                0L);
         processAllMessages();
         synchronized (mLock) {
             if (!mReceivedTestIntent) {
@@ -402,15 +415,48 @@
             }
             assertEquals(true, mReceivedTestIntent);
             int resultCode = mTestReceiver.getResultCode();
-            assertTrue("Unexpected result code: " + resultCode,
-                    resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK);
-            verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
-                    any(Message.class));
+            verify(mSimulatedCommandsVerifier, times(0))
+                    .sendSMS(anyString(), anyString(), any(Message.class));
+            return resultCode;
         }
     }
 
     @Test
     @SmallTest
+    @Ignore("b/256282780")
+    public void testSendSmsByCarrierApp() throws Exception {
+        int resultCode = sendSmsWithCarrierAppResponse(CarrierMessagingService.SEND_STATUS_OK);
+        assertTrue(
+                "Unexpected result code: " + resultCode,
+                resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK);
+    }
+
+    @Test
+    @SmallTest
+    public void testSendSmsByCarrierApp_PermanentFailure() throws Exception {
+        int resultCode = sendSmsWithCarrierAppResponse(CarrierMessagingService.SEND_STATUS_ERROR);
+        assertTrue(
+                "Unexpected result code: " + resultCode,
+                resultCode == SmsManager.RESULT_RIL_GENERIC_ERROR);
+    }
+
+    @Test
+    @SmallTest
+    public void testSendSmsByCarrierApp_FailureWithReason() throws Exception {
+        if (!Flags.temporaryFailuresInCarrierMessagingService()) {
+            return;
+        }
+        doReturn(true).when(mFeatureFlags).temporaryFailuresInCarrierMessagingService();
+        int resultCode =
+                sendSmsWithCarrierAppResponse(
+                        CarrierMessagingService.SEND_STATUS_RESULT_ERROR_NO_SERVICE);
+        assertTrue(
+                "Unexpected result code: " + resultCode,
+                resultCode == SmsManager.RESULT_ERROR_NO_SERVICE);
+    }
+
+    @Test
+    @SmallTest
     public void testSendSmsByCarrierAppNoResponse() throws Exception {
         mockCarrierApp();
         // do not mock result, instead reduce the timeout for test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 876410c..cf6f6a9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -1702,6 +1702,7 @@
 
     @Test
     public void testRegisterForSatelliteProvisionStateChanged() {
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         Semaphore semaphore = new Semaphore(0);
         ISatelliteProvisionStateCallback callback =
                 new ISatelliteProvisionStateCallback.Stub() {
@@ -1753,7 +1754,6 @@
         processAllMessages();
         assertTrue(waitForForEvents(
                 semaphore, 1, "testRegisterForSatelliteProvisionStateChanged"));
-
         mSatelliteControllerUT.unregisterForSatelliteProvisionStateChanged(callback);
         semaphore.drainPermits();
         cancelRemote = mSatelliteControllerUT.provisionSatelliteService(
@@ -3650,7 +3650,10 @@
 
     @Test
     public void testHandleEventServiceStateChanged() {
+        mContextFixture.putBooleanResource(
+            R.bool.config_satellite_should_notify_availability, true);
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         mCarrierConfigBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
                 CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC);
         invokeCarrierConfigChanged();
@@ -4145,6 +4148,8 @@
 
     @Test
     public void testNotifyNtnEligibilityHysteresisTimedOut() {
+        mContextFixture.putBooleanResource(
+            R.bool.config_satellite_should_notify_availability, true);
         when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
         when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
@@ -4569,6 +4574,18 @@
                 }
             }
         };
+
+        TestSubscriptionManager testSubscriptionManager = new TestSubscriptionManager();
+        doAnswer(invocation -> {
+            testSubscriptionManager.setIsSatelliteProvisionedForNonIpDatagram(
+                    invocation.getArgument(0), invocation.getArgument(1));
+            return null;
+        }).when(mMockSubscriptionManagerService).setIsSatelliteProvisionedForNonIpDatagram(anyInt(),
+                anyBoolean());
+        doAnswer(invocation -> testSubscriptionManager.isSatelliteProvisionedForNonIpDatagram(
+                invocation.getArgument(0))).when(
+                mMockSubscriptionManagerService).isSatelliteProvisionedForNonIpDatagram(anyInt());
+
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged(callback);
@@ -6022,4 +6039,21 @@
         assertTrue(mSharedPreferences.getBoolean(
                 SatelliteController.NTN_SMS_SUPPORTED_BY_MESSAGES_APP_KEY, false));
     }
+
+    private static class TestSubscriptionManager {
+        public Map<Integer, Boolean> mSatelliteProvisionedForNonIpDatagram = new HashMap<>();
+
+        public void resetProvisionMapForNonIpDatagram() {
+            mSatelliteProvisionedForNonIpDatagram.clear();
+        }
+
+        public void setIsSatelliteProvisionedForNonIpDatagram(int subId, boolean provisioned) {
+            mSatelliteProvisionedForNonIpDatagram.put(subId, provisioned);
+        }
+
+        public boolean isSatelliteProvisionedForNonIpDatagram(int subId) {
+            Boolean isProvisioned = mSatelliteProvisionedForNonIpDatagram.get(subId);
+            return isProvisioned != null ? isProvisioned : false;
+        }
+    }
 }