Merge "Add exception handling for radio power off during emergency call" into main
diff --git a/OWNERS b/OWNERS
index ff1a04e..aa0dee2 100644
--- a/OWNERS
+++ b/OWNERS
@@ -18,4 +18,4 @@
 xiaotonj@google.com
 
 # Domain Selection code is co-owned, adding additional owners for this code
-per-file EmergencyStateTracker*=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,jdyou@google.com
+per-file EmergencyStateTracker*=hwangoo@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,jdyou@google.com
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 17dffa4..574cd63 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -10,6 +10,14 @@
   is_fixed_read_only: true
 }
 
+# OWNER=tnd TARGET=24Q1
+flag {
+  name: "log_mms_sms_database_access_info"
+  namespace: "telephony"
+  description: "Whether to log MMS/SMS database access info and report anomaly when getting exception."
+  bug: "275225402"
+}
+
 # OWNER=tjstuart TARGET=24Q3
 flag {
   name: "stop_spamming_emergency_notification"
@@ -35,14 +43,6 @@
   bug: "309655251"
 }
 
-# OWNER=nagendranb TARGET=24Q3
-flag {
-  name: "enable_telephony_analytics"
-  namespace: "telephony"
-  description: "Enable Telephony Analytics information of Service State , Sms and Call scenarios"
-  bug: "309896524"
-}
-
 # OWNER=rambowang TARGET=24Q3
 flag {
     name: "reset_mobile_network_settings"
@@ -52,25 +52,6 @@
     bug:"271921464"
 }
 
-# OWNER=sangyun TARGET=24Q3
-flag {
-    name: "roaming_notification_for_single_data_network"
-    namespace: "telephony"
-    description: "Fix bug where roaming notification was not shown on a single data network."
-    bug:"249908996"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-# OWNER=joonhunshin TARGET=24Q3
-flag {
-    name: "enforce_telephony_feature_mapping"
-    namespace: "telephony"
-    description: "This flag controls telephony feature flags mapping."
-    bug:"297989574"
-}
-
 # OWNER=joonhunshin TARGET=24Q3
 flag {
     name: "enforce_telephony_feature_mapping_for_public_apis"
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index c2a422d..8451bed 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -671,9 +671,7 @@
             mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
         }
         //Initialize Telephony Analytics
-        if (mFeatureFlags.enableTelephonyAnalytics()) {
-            mTelephonyAnalytics = new TelephonyAnalytics(this);
-        }
+        mTelephonyAnalytics = new TelephonyAnalytics(this);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index d4ef3be..ac0ee0d 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -5345,7 +5345,7 @@
     public void setSatellitePlmn(int simSlot, @NonNull List<String> carrierPlmnList,
             @NonNull List<String> allSatellitePlmnList, Message result) {
         RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
-        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_4)) {
+        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_3)) {
             riljLog("setSatellitePlmn: SatelliteModemInterface is used.");
             SatelliteModemInterface.getInstance().setSatellitePlmn(
                     simSlot, carrierPlmnList, allSatellitePlmnList, result);
@@ -5378,7 +5378,7 @@
     public void setSatelliteEnabledForCarrier(int simSlot, boolean satelliteEnabled,
             Message result) {
         RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
-        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_4)) {
+        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_3)) {
             riljLog("setSatelliteEnabledForCarrier: SatelliteModemInterface is used.");
             SatelliteModemInterface.getInstance().requestSetSatelliteEnabledForCarrier(
                     simSlot, satelliteEnabled, result);
@@ -5408,7 +5408,7 @@
     @Override
     public void isSatelliteEnabledForCarrier(int simSlot, Message result) {
         RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
-        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_4)) {
+        if (getHalVersion(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_2_3)) {
             riljLog("isSatelliteEnabledForCarrier: SatelliteModemInterface is used.");
             SatelliteModemInterface.getInstance().requestIsSatelliteEnabledForCarrier(
                     simSlot, result);
diff --git a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
index 0beb176..10224cb 100644
--- a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
+++ b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
@@ -44,6 +45,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyDisplayInfo;
+import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.LocalLog;
 
@@ -100,6 +102,38 @@
                     EVALUATION_REASON_VOICE_CALL_END})
     public @interface AutoDataSwitchEvaluationReason {}
 
+    /**
+     * Defines the switch type for considering a subscription as out of service before switching
+     * data, in milliseconds.
+     * If one SIM has service while the other is out of service for this duration,
+     * data will be switched to the SIM with service.
+     */
+    private static final int STABILITY_CHECK_AVAILABILITY_SWITCH = 0;
+    /**
+     * Defines the switch type for considering the RAT and signal strength advantage of a
+     * subscription to be stable before switching data, in milliseconds.
+     * Each RAT and signal strength is assigned a score. If one SIM's score is higher
+     * than the other SIM's score for this duration, data will be switched to that SIM.
+     */
+    private static final int STABILITY_CHECK_PERFORMANCE_SWITCH = 1;
+    /**
+     * Defines the switch type for switching data back to the default SIM when both SIMs are out of
+     * service, in milliseconds.
+     * If the current data is on the backup SIM and both SIMs remain out of service,
+     * data will be switched back to the default SIM.
+     */
+    private static final int STABILITY_CHECK_AVAILABILITY_SWITCH_BACK = 2;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "STABILITY_CHECK_",
+            value = {STABILITY_CHECK_AVAILABILITY_SWITCH,
+                    STABILITY_CHECK_PERFORMANCE_SWITCH,
+                    STABILITY_CHECK_AVAILABILITY_SWITCH_BACK,
+            })
+    public @interface PreSwitchStabilityCheckType {}
+
+    /** stability check type to timer in milliseconds. */
+    private static final Map<Integer, Long> STABILITY_CHECK_TIMER_MAP = new ArrayMap<>();
+
     private static final String LOG_TAG = "ADSC";
 
     /** Event for service state changed. */
@@ -160,11 +194,22 @@
     /**
      * Event extras for checking environment stability.
      * @param targetPhoneId The target phone Id to switch to when the stability check pass.
-     * @param isForPerformance Whether the switch is due to RAT/signal strength performance.
+     * @param switchType Whether the switch is due to OOS, RAT/signal strength performance, or
+     *                   switch back.
      * @param needValidation Whether ping test needs to pass.
      */
-    private record StabilityEventExtra(int targetPhoneId, boolean isForPerformance,
-                               boolean needValidation) {}
+    private record StabilityEventExtra(int targetPhoneId,
+                                       @PreSwitchStabilityCheckType int switchType,
+                                       boolean needValidation) {
+        @Override
+        public String toString() {
+            return "StabilityEventExtra{"
+                    + "targetPhoneId=" + targetPhoneId
+                    + ", switchType=" + switchTypeToString(switchType)
+                    + ", needValidation=" + needValidation
+                    + "}";
+        }
+    }
 
     /**
      * Event extras for evaluating switch environment.
@@ -175,18 +220,6 @@
     /** {@code true} if we've displayed the notification the first time auto switch occurs **/
     private boolean mDisplayedNotification = false;
     /**
-     * Configurable time threshold in ms to define an internet connection status to be stable(e.g.
-     * out of service, in service, wifi is the default active network.etc), while -1 indicates auto
-     * switch feature disabled.
-     */
-    private long mAutoDataSwitchAvailabilityStabilityTimeThreshold = -1;
-    /**
-     * Configurable time threshold in ms to define an internet connection performance status to be
-     * stable (e.g. LTE + 4 signal strength, UMTS + 2 signal strength), while -1 indicates
-     * auto switch feature based on RAT/SS is disabled.
-     */
-    private long mAutoDataSwitchPerformanceStabilityTimeThreshold = -1;
-    /**
      * The tolerated gap of score for auto data switch decision, larger than which the device will
      * switch to the SIM with higher score. If 0, the device will always switch to the higher score
      * SIM. If < 0, the network type and signal strength based auto switch is disabled.
@@ -462,10 +495,14 @@
         mScoreTolerance = dataConfig.getAutoDataSwitchScoreTolerance();
         mRequirePingTestBeforeSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired();
         mAllowNddsRoaming = dataConfig.doesAutoDataSwitchAllowRoaming();
-        mAutoDataSwitchAvailabilityStabilityTimeThreshold =
-                dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold();
-        mAutoDataSwitchPerformanceStabilityTimeThreshold =
-                dataConfig.getAutoDataSwitchPerformanceStabilityTimeThreshold();
+        STABILITY_CHECK_TIMER_MAP.put(STABILITY_CHECK_AVAILABILITY_SWITCH,
+                dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold());
+        STABILITY_CHECK_TIMER_MAP.put(STABILITY_CHECK_PERFORMANCE_SWITCH,
+                dataConfig.getAutoDataSwitchPerformanceStabilityTimeThreshold());
+        STABILITY_CHECK_TIMER_MAP.put(STABILITY_CHECK_AVAILABILITY_SWITCH_BACK,
+                dataConfig.getAutoDataSwitchAvailabilitySwitchbackStabilityTimeThreshold() >= 0
+                        ? dataConfig.getAutoDataSwitchAvailabilitySwitchbackStabilityTimeThreshold()
+                        : dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold());
         mAutoDataSwitchValidationMaxRetry =
                 dataConfig.getAutoDataSwitchValidationMaxRetry();
     }
@@ -628,7 +665,7 @@
      */
     public void evaluateAutoDataSwitch(@AutoDataSwitchEvaluationReason int reason) {
         long delayMs = reason == EVALUATION_REASON_RETRY_VALIDATION
-                ? mAutoDataSwitchAvailabilityStabilityTimeThreshold
+                ? STABILITY_CHECK_TIMER_MAP.get(STABILITY_CHECK_AVAILABILITY_SWITCH)
                 << mAutoSwitchValidationFailedCount
                 : 0;
         if (!mScheduledEventsToExtras.containsKey(EVENT_EVALUATE_AUTO_SWITCH)) {
@@ -645,7 +682,7 @@
      */
     private void onEvaluateAutoDataSwitch(@AutoDataSwitchEvaluationReason int reason) {
         // auto data switch feature is disabled.
-        if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return;
+        if (STABILITY_CHECK_TIMER_MAP.get(STABILITY_CHECK_AVAILABILITY_SWITCH) < 0) return;
         int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId();
         // check is valid DSDS
         if (mSubscriptionManagerService.getActiveSubIdList(true).length < 2) return;
@@ -669,7 +706,7 @@
             log(debugMessage.toString());
             if (res.targetPhoneId != INVALID_PHONE_INDEX) {
                 mSelectedTargetPhoneId = res.targetPhoneId;
-                startStabilityCheck(res.targetPhoneId, res.isForPerformance, res.needValidation);
+                startStabilityCheck(res.targetPhoneId, res.switchType, res.needValidation);
             } else {
                 cancelAnyPendingSwitch();
             }
@@ -690,8 +727,7 @@
                 log(debugMessage.append(
                         ", immediately back to default as user turns off default").toString());
                 return;
-            } else if (!(internetEvaluation = backupDataPhone.getDataNetworkController()
-                    .getInternetEvaluation(false/*ignoreExistingNetworks*/))
+            } else if (!(internetEvaluation = getInternetEvaluation(backupDataPhone))
                     .isSubsetOf(DataEvaluation.DataDisallowedReason.NOT_IN_SERVICE)) {
                 mSelectedTargetPhoneId = INVALID_PHONE_INDEX;
                 mPhoneSwitcherCallback.onRequireImmediatelySwitchToPhone(
@@ -703,7 +739,7 @@
             }
 
             boolean backToDefault = false;
-            boolean isForPerformance = false;
+            int switchType = STABILITY_CHECK_AVAILABILITY_SWITCH;
             boolean needValidation = true;
 
             if (isNddsRoamingEnabled()) {
@@ -747,7 +783,7 @@
                                             .append(defaultScore).append(" versus current ")
                                             .append(currentScore);
                                     backToDefault = true;
-                                    isForPerformance = true;
+                                    switchType = STABILITY_CHECK_PERFORMANCE_SWITCH;
                                     needValidation = mRequirePingTestBeforeSwitch;
                                 }
                             } else {
@@ -759,6 +795,7 @@
                         } else {
                             debugMessage.append(", back to default as both phones are unusable.");
                             backToDefault = true;
+                            switchType = STABILITY_CHECK_AVAILABILITY_SWITCH_BACK;
                             needValidation = false;
                         }
                     }
@@ -782,7 +819,7 @@
                                 .append(defaultScore).append(" versus current ")
                                 .append(currentScore);
                         backToDefault = true;
-                        isForPerformance = true;
+                        switchType = STABILITY_CHECK_PERFORMANCE_SWITCH;
                         needValidation = mRequirePingTestBeforeSwitch;
                     }
                 } else if (isInService(mPhonesSignalStatus[defaultDataPhoneId].mDataRegState)) {
@@ -795,7 +832,7 @@
             if (backToDefault) {
                 log(debugMessage.toString());
                 mSelectedTargetPhoneId = defaultDataPhoneId;
-                startStabilityCheck(DEFAULT_PHONE_INDEX, isForPerformance, needValidation);
+                startStabilityCheck(DEFAULT_PHONE_INDEX, switchType, needValidation);
             } else {
                 // cancel any previous attempts of switching back to default phone
                 cancelAnyPendingSwitch();
@@ -812,9 +849,9 @@
     @NonNull private StabilityEventExtra evaluateAnyCandidateToUse(int defaultPhoneId,
             @NonNull StringBuilder debugMessage) {
         Phone defaultDataPhone = PhoneFactory.getPhone(defaultPhoneId);
-        boolean isForPerformance = false;
+        int switchType = STABILITY_CHECK_AVAILABILITY_SWITCH;
         StabilityEventExtra invalidResult = new StabilityEventExtra(INVALID_PHONE_INDEX,
-                isForPerformance, mRequirePingTestBeforeSwitch);
+                switchType, mRequirePingTestBeforeSwitch);
 
         if (defaultDataPhone == null) {
             debugMessage.append(", no candidate as no sim loaded");
@@ -874,7 +911,7 @@
                         debugMessage.append(" with ").append(defaultScore)
                                 .append(" versus candidate higher score ").append(candidateScore);
                         secondaryDataPhone = PhoneFactory.getPhone(phoneId);
-                        isForPerformance = true;
+                        switchType = STABILITY_CHECK_PERFORMANCE_SWITCH;
                     } else {
                         debugMessage.append(", candidate's score ").append(candidateScore)
                                 .append(" doesn't justify the switch given the current ")
@@ -895,7 +932,7 @@
                             debugMessage.append(" with higher score ").append(candidateScore)
                                     .append(" versus current ").append(defaultScore);
                             secondaryDataPhone = PhoneFactory.getPhone(phoneId);
-                            isForPerformance = true;
+                            switchType = STABILITY_CHECK_PERFORMANCE_SWITCH;
                         } else {
                             debugMessage.append(", but its score ").append(candidateScore)
                                     .append(" doesn't meet the bar to switch given the current ")
@@ -909,15 +946,14 @@
             }
 
             if (secondaryDataPhone != null) {
+                DataEvaluation evaluation = getInternetEvaluation(secondaryDataPhone);
                 // check internet data is allowed on the candidate
-                DataEvaluation internetEvaluation = secondaryDataPhone.getDataNetworkController()
-                        .getInternetEvaluation(false/*ignoreExistingNetworks*/);
-                if (!internetEvaluation.containsDisallowedReasons()) {
+                if (!evaluation.containsDisallowedReasons()) {
                     return new StabilityEventExtra(phoneId,
-                            isForPerformance, mRequirePingTestBeforeSwitch);
+                            switchType, mRequirePingTestBeforeSwitch);
                 } else {
                     debugMessage.append(", but candidate's data is not allowed ")
-                            .append(internetEvaluation);
+                            .append(evaluation);
                 }
             }
         }
@@ -926,10 +962,31 @@
     }
 
     /**
+     * Get internet evaluation base on phone's satellite/terrestrial env.
+     * @param phone the target phone
+     * @return internet evaluation.
+     */
+    @NonNull
+    private DataEvaluation getInternetEvaluation(@NonNull Phone phone) {
+        NetworkRequest.Builder reqBuilder = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+        if (phone.getServiceState().isUsingNonTerrestrialNetwork()) {
+            // When satellite, RCS requests are restricted.
+            reqBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
+        return phone.getDataNetworkController().evaluateNetworkRequest(
+                new TelephonyNetworkRequest(reqBuilder.build(), phone, sFeatureFlags),
+                DataEvaluation.DataEvaluationReason.EXTERNAL_QUERY);
+    }
+
+    /**
      * @return {@code true} If the feature of switching base on RAT and signal strength is enabled.
      */
     private boolean isRatSignalStrengthBasedSwitchEnabled() {
-        return mScoreTolerance >= 0 && mAutoDataSwitchPerformanceStabilityTimeThreshold >= 0
+        return mScoreTolerance >= 0
+                && STABILITY_CHECK_TIMER_MAP.get(STABILITY_CHECK_PERFORMANCE_SWITCH) >= 0
                 && sFeatureFlags.autoDataSwitchEnhanced();
     }
 
@@ -943,29 +1000,27 @@
     /**
      * Called when the current environment suits auto data switch.
      * Start pre-switch validation if the current environment suits auto data switch for
-     * {@link #mAutoDataSwitchAvailabilityStabilityTimeThreshold} MS.
+     * {@link #STABILITY_CHECK_TIMER_MAP} MS.
      * @param targetPhoneId the target phone Id.
-     * @param isForPerformance {@code true} entails longer stability check.
+     * @param switchType {@code true} determines stability check timer.
      * @param needValidation {@code true} if validation is needed.
      */
-    private void startStabilityCheck(int targetPhoneId, boolean isForPerformance,
+    private void startStabilityCheck(int targetPhoneId, @PreSwitchStabilityCheckType int switchType,
             boolean needValidation) {
         StabilityEventExtra eventExtras = (StabilityEventExtra)
                 mScheduledEventsToExtras.getOrDefault(EVENT_STABILITY_CHECK_PASSED,
-                        new StabilityEventExtra(INVALID_PHONE_INDEX, false /*need validation*/,
+                        new StabilityEventExtra(INVALID_PHONE_INDEX, -1 /*invalid switch type*/,
                                 false /*isForPerformance*/));
         long delayMs = -1;
         // Check if already scheduled one with that combination of extras.
         if (eventExtras.targetPhoneId != targetPhoneId
                 || eventExtras.needValidation != needValidation
-                || eventExtras.isForPerformance != isForPerformance) {
+                || eventExtras.switchType != switchType) {
             eventExtras =
-                    new StabilityEventExtra(targetPhoneId, isForPerformance, needValidation);
+                    new StabilityEventExtra(targetPhoneId, switchType, needValidation);
 
             // Reset with new timer.
-            delayMs = isForPerformance
-                    ? mAutoDataSwitchPerformanceStabilityTimeThreshold
-                    : mAutoDataSwitchAvailabilityStabilityTimeThreshold;
+            delayMs = STABILITY_CHECK_TIMER_MAP.get(switchType);
             scheduleEventWithTimer(EVENT_STABILITY_CHECK_PASSED, eventExtras, delayMs);
         }
         log("startStabilityCheck: "
@@ -1158,6 +1213,17 @@
         return phoneId >= 0 && phoneId < mPhonesSignalStatus.length;
     }
 
+    /** Auto data switch stability check type to string. */
+    @NonNull
+    public static String switchTypeToString(@PreSwitchStabilityCheckType int switchType) {
+        return switch (switchType) {
+            case STABILITY_CHECK_AVAILABILITY_SWITCH -> "AVAILABILITY_SWITCH";
+            case STABILITY_CHECK_PERFORMANCE_SWITCH -> "PERFORMANCE_SWITCH";
+            case STABILITY_CHECK_AVAILABILITY_SWITCH_BACK -> "AVAILABILITY_SWITCH_BACK";
+            default -> "Unknown(" + switchType + ")";
+        };
+    }
+
     /**
      * Log debug messages.
      * @param s debug messages
@@ -1198,8 +1264,9 @@
         pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry
                 + " mAutoSwitchValidationFailedCount=" + mAutoSwitchValidationFailedCount);
         pw.println("mRequirePingTestBeforeDataSwitch=" + mRequirePingTestBeforeSwitch);
-        pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold="
-                + mAutoDataSwitchAvailabilityStabilityTimeThreshold);
+        pw.println("STABILITY_CHECK_TIMER_MAP:");
+        STABILITY_CHECK_TIMER_MAP.forEach((key, value)
+                -> pw.println(switchTypeToString(key) + ": " + value));
         pw.println("mSelectedTargetPhoneId=" + mSelectedTargetPhoneId);
         pw.increaseIndent();
         for (PhoneSignalStatus status: mPhonesSignalStatus) {
diff --git a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
index 99578cf..3ab5283 100644
--- a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
+++ b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
@@ -273,7 +273,8 @@
 
         mNetworkCallback = new ConnectivityNetworkCallback(subId);
 
-        mConnectivityManager.requestNetwork(createNetworkRequest(), mNetworkCallback, mHandler);
+        mConnectivityManager.requestNetwork(
+                createNetworkRequest(subId), mNetworkCallback, mHandler);
         mHandler.postDelayed(() -> onValidationTimeout(subId), timeoutInMs);
     }
 
@@ -314,13 +315,22 @@
         return mState != STATE_IDLE;
     }
 
-    private NetworkRequest createNetworkRequest() {
-        return new NetworkRequest.Builder()
+    private NetworkRequest createNetworkRequest(int subId) {
+        NetworkRequest.Builder req = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
-                        .setSubscriptionId(mSubId).build())
-                .build();
+                        .setSubscriptionId(subId).build());
+
+        // Satellite is considered valid as long as it can serve restricted requests.
+        Phone target = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
+        boolean isSatellite = target != null
+                && target.getServiceState().isUsingNonTerrestrialNetwork();
+        if (isSatellite) {
+            req.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE)
+                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+        return req.build();
     }
 
     private synchronized void reportValidationResult(boolean passed, int subId) {
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 8e4a16d..fe7220e 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -1162,6 +1162,19 @@
     }
 
     /**
+     * Defines the threshold for switching data back to the default SIM when both SIMs are out of
+     * service, in milliseconds.
+     * If the current data is on the backup SIM and both SIMs remain out of service for this
+     * duration, data will be switched back to the default SIM.
+     * A value of 0 means an immediate switch. If the value is negative, the threshold defined by
+     * {@link #getAutoDataSwitchAvailabilityStabilityTimeThreshold()} will be used instead.
+     */
+    public long getAutoDataSwitchAvailabilitySwitchbackStabilityTimeThreshold() {
+        return mResources.getInteger(com.android.internal.R.integer
+                .auto_data_switch_availability_switchback_stability_time_threshold_millis);
+    }
+
+    /**
      * Get the TCP config string, used by {@link LinkProperties#setTcpBufferSizes(String)}.
      * The config string will have the following form, with values in bytes:
      * "read_min,read_default,read_max,write_min,write_default,write_max"
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 3ffb6df..392b996 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -1593,7 +1593,8 @@
      * @return The data evaluation result.
      */
     @NonNull
-    private DataEvaluation evaluateNetworkRequest(
+    @VisibleForTesting
+    public DataEvaluation evaluateNetworkRequest(
             @NonNull TelephonyNetworkRequest networkRequest, DataEvaluationReason reason) {
         DataEvaluation evaluation = new DataEvaluation(reason);
         int transport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
@@ -2289,6 +2290,9 @@
         }
         // When the device is on satellite, internet with restricted capabilities always honor
         // soft disallowed reasons and not respected as restricted request
+        // Note - ping test are performed with restricted request on satellite assuming they cannot
+        // bypass any checks. If below is removed, reevaluate the ping request in
+        // CellularNetworkValidator and the getInternetEvaluation in AutoDataSwitchController
         return !(mServiceState.isUsingNonTerrestrialNetwork()
                 && networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
     }
diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java
index 0b9ac27..0372bc6 100644
--- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java
+++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java
@@ -216,7 +216,6 @@
                 break;
             }
             case EVENT_SUBSCRIPTIONS_CHANGED: {
-                mSubId = (int) msg.obj;
                 refreshEnabledMobileDataPolicy();
                 updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER,
                         mPhone.getContext().getOpPackageName(),
@@ -313,11 +312,12 @@
                     public void onSubscriptionsChanged() {
                         if (mSubId != mPhone.getSubId()) {
                             log("onSubscriptionsChanged: " + mSubId + " to " + mPhone.getSubId());
+                            mSubId = mPhone.getSubId();
                             obtainMessage(EVENT_SUBSCRIPTIONS_CHANGED, mPhone.getSubId())
                                     .sendToTarget();
                         }
                     }
-                }, this::post);
+                }, Runnable::run);
         // some overall mobile data override policy depend on whether DDS is user data enabled.
         for (Phone phone : PhoneFactory.getPhones()) {
             if (phone.getPhoneId() != mPhone.getPhoneId()) {
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index acd3fd1..370f0a1 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -34,7 +34,6 @@
 import android.os.Build;
 import android.os.Looper;
 import android.os.SystemProperties;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.satellite.ISatelliteDatagramCallback;
@@ -180,11 +179,7 @@
         mDatagramWaitTimeForConnectedStateForLastMessage =
                 getDatagramWaitForConnectedStateForLastMessageTimeoutMillis();
         mDemoModeDatagramList = new ArrayList<>();
-
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
     }
 
     /**
@@ -694,19 +689,6 @@
         Rlog.e(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index d1d8726..a6b4efb 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -28,8 +28,8 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
-import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
 import static com.android.internal.telephony.SmsDispatchersController.PendingRequest;
+import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -39,7 +39,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.satellite.SatelliteDatagram;
@@ -194,10 +193,7 @@
         mDatagramController = datagramController;
         mControllerMetricsStats = ControllerMetricsStats.getInstance();
         mSessionMetricsStats = SessionMetricsStats.getInstance();
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
 
         synchronized (mLock) {
             mSendingInProgress = false;
@@ -1409,19 +1405,6 @@
 
     private static void logw(@NonNull String log) { Rlog.w(TAG, log); }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index c01f10d..9995c4f 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -37,7 +37,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.provider.Telephony;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
@@ -152,10 +151,7 @@
         mDatagramController = datagramController;
         mControllerMetricsStats = ControllerMetricsStats.getInstance();
         mSessionMetricsStats = SessionMetricsStats.getInstance();
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
         try {
             mSharedPreferences =
                     mContext.getSharedPreferences(SatelliteController.SATELLITE_SHARED_PREF,
@@ -907,19 +903,6 @@
         Rlog.w(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
index 9606150..dd30793 100644
--- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java
+++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
@@ -35,7 +35,6 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
@@ -122,10 +121,7 @@
         mLastIsEmergency = false;
         mListenerForPointingUIRegistered = false;
         mActivityManager = mContext.getSystemService(ActivityManager.class);
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
     }
 
     /**
@@ -565,19 +561,6 @@
         Rlog.e(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index bd0f766..f0822a9 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -860,11 +860,7 @@
             @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) {
         super(looper);
 
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
-
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
         mContext = context;
         mFeatureFlags = featureFlags;
         Phone phone = SatelliteServiceUtils.getPhone();
@@ -5817,12 +5813,6 @@
                     + "SetSatelliteAttachEnableForCarrier error code =" + errorCode);
         }
 
-        if (!isSatelliteSupportedViaCarrier(subId)) {
-            plogd("Satellite for carrier is not supported. Only user setting is stored");
-            callback.accept(SATELLITE_RESULT_SUCCESS);
-            return;
-        }
-
         Phone phone = SatelliteServiceUtils.getPhone(subId);
         if (phone == null) {
             ploge("evaluateEnablingSatelliteForCarrier: phone is null for subId=" + subId);
@@ -5832,23 +5822,20 @@
 
         /* Request to enable or disable the satellite in the cellular modem only when the desired
         state and the current state are different. */
-        boolean isSatelliteExpectedToBeEnabled = !isSatelliteRestrictedForCarrier(subId);
+        boolean isSatelliteExpectedToBeEnabled = !isSatelliteRestrictedForCarrier(subId)
+                && isSatelliteSupportedViaCarrier(subId);
         if (isSatelliteExpectedToBeEnabled != isSatelliteEnabledForCarrierAtModem(subId)) {
-            if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                int simSlot = SubscriptionManager.getSlotIndex(subId);
-                RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
-                        new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId,
-                                reason, callback);
-                SatelliteControllerHandlerRequest request =
-                        new SatelliteControllerHandlerRequest(argument,
-                                SatelliteServiceUtils.getPhone(subId));
-                Message onCompleted = obtainMessage(
-                        EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE, request);
-                phone.setSatelliteEnabledForCarrier(simSlot,
-                        isSatelliteExpectedToBeEnabled, onCompleted);
-            } else {
-                callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            }
+            int simSlot = SubscriptionManager.getSlotIndex(subId);
+            RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
+                    new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId,
+                            reason, callback);
+            SatelliteControllerHandlerRequest request =
+                    new SatelliteControllerHandlerRequest(argument,
+                            SatelliteServiceUtils.getPhone(subId));
+            Message onCompleted = obtainMessage(
+                    EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE, request);
+            phone.setSatelliteEnabledForCarrier(simSlot,
+                    isSatelliteExpectedToBeEnabled, onCompleted);
         } else {
             callback.accept(SATELLITE_RESULT_SUCCESS);
         }
@@ -6935,19 +6922,6 @@
         Rlog.e(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 5b032e6..9ceca72 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -30,7 +30,6 @@
 import android.os.Message;
 import android.os.RegistrantList;
 import android.os.RemoteException;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.IBooleanConsumer;
 import android.telephony.IIntegerConsumer;
 import android.telephony.PersistentLogger;
@@ -255,10 +254,7 @@
             SatelliteController satelliteController,
             @NonNull Looper looper,
             @NonNull FeatureFlags featureFlags) {
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
         mContext = context;
         mDemoSimulator = DemoSimulator.make(context, satelliteController);
         mVendorListener = new SatelliteListener(false);
@@ -1437,19 +1433,6 @@
         Rlog.e(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index fc79c49..03c294b 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -28,7 +28,6 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
 
-import static com.android.internal.telephony.flags.Flags.satellitePersistentLogging;
 import static com.android.internal.telephony.satellite.SatelliteController.INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
 
 import android.annotation.NonNull;
@@ -48,7 +47,6 @@
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
 import android.telecom.Connection;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -74,7 +72,6 @@
 import com.android.internal.telephony.SmsApplication;
 import com.android.internal.telephony.TelephonyCountryDetector;
 import com.android.internal.telephony.flags.FeatureFlags;
-import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.metrics.SatelliteStats;
 
 import java.util.Arrays;
@@ -160,10 +157,7 @@
             @NonNull SatelliteController satelliteController,
             ImsManager imsManager) {
         super(looper);
-        if (isSatellitePersistentLoggingEnabled(context)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
         mContext = context;
         mSatelliteController = satelliteController;
         mFeatureFlags = mSatelliteController.getFeatureFlags();
@@ -869,19 +863,6 @@
         Rlog.e(TAG, log);
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context) {
-        if (satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private void plogd(@NonNull String log) {
         Rlog.d(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index dd58151..3e77bd9 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -30,7 +30,9 @@
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellIdentity;
+import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -51,6 +53,8 @@
 import android.telephony.satellite.stub.SatelliteResult;
 import android.text.TextUtils;
 
+import com.android.internal.R;
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
@@ -315,6 +319,10 @@
             if (ar.exception instanceof SatelliteManager.SatelliteException) {
                 errorCode = ((SatelliteManager.SatelliteException) ar.exception).getErrorCode();
                 loge(caller + " SatelliteException: " + ar.exception);
+            } else if (ar.exception instanceof CommandException) {
+                errorCode = convertCommandExceptionErrorToSatelliteError(
+                        ((CommandException) ar.exception).getCommandError());
+                loge(caller + " CommandException: "  + ar.exception);
             } else {
                 loge(caller + " unknown exception: " + ar.exception);
             }
@@ -323,6 +331,27 @@
         return errorCode;
     }
 
+    private static int convertCommandExceptionErrorToSatelliteError(
+            CommandException.Error commandExceptionError) {
+        logd("convertCommandExceptionErrorToSatelliteError: commandExceptionError="
+                + commandExceptionError.toString());
+
+        switch(commandExceptionError) {
+            case REQUEST_NOT_SUPPORTED:
+                return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
+            case RADIO_NOT_AVAILABLE:
+                return SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE;
+            case INTERNAL_ERR:
+            case INVALID_STATE:
+            case INVALID_MODEM_STATE:
+                return SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE;
+            case MODEM_ERR:
+                return SatelliteManager.SATELLITE_RESULT_MODEM_ERROR;
+            default:
+                return SatelliteManager.SATELLITE_RESULT_ERROR;
+        }
+    }
+
     /**
      * Get valid subscription id for satellite communication.
      *
@@ -662,6 +691,26 @@
         return earfcnsMap;
     }
 
+    /**
+     * Returns a persistent logger to persist important log because logcat logs may not be
+     * retained long enough.
+     *
+     * @return a PersistentLogger, return {@code null} if it is not supported or encounters
+     * exception.
+     */
+    @Nullable
+    public static PersistentLogger getPersistentLogger(@NonNull Context context) {
+        try {
+            if (context.getResources().getBoolean(
+                    R.bool.config_dropboxmanager_persistent_logging_enabled)) {
+                return new PersistentLogger(DropBoxManagerLoggerBackend.getInstance(context));
+            }
+        } catch (RuntimeException ex) {
+            loge("getPersistentLogger: RuntimeException ex=" + ex);
+        }
+        return null;
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
index ed3129a..57e768c 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
@@ -30,8 +30,8 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS;
-import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE;
@@ -59,7 +59,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.WorkSource;
-import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PersistentLogger;
 import android.telephony.ServiceState;
@@ -274,11 +273,7 @@
             @NonNull SatelliteModemInterface satelliteModemInterface) {
         super(TAG, looper);
 
-        if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
-            mPersistentLogger = new PersistentLogger(
-                    DropBoxManagerLoggerBackend.getInstance(context));
-        }
-
+        mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
         mContext = context;
         mFeatureFlags = featureFlags;
         mSatelliteModemInterface = satelliteModemInterface;
@@ -2027,19 +2022,6 @@
         return true;
     }
 
-    private boolean isSatellitePersistentLoggingEnabled(
-            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
-        if (featureFlags.satellitePersistentLogging()) {
-            return true;
-        }
-        try {
-            return context.getResources().getBoolean(
-                    R.bool.config_dropboxmanager_persistent_logging_enabled);
-        } catch (RuntimeException e) {
-            return false;
-        }
-    }
-
     private boolean isConcurrentTnScanningSupported() {
         try {
             return mContext.getResources().getBoolean(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
index ec5adae..916d51d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
@@ -48,7 +48,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG);
         mSubscriptionInfoUT = new SubscriptionInfo.Builder()
                 .setId(1)
                 .setIccId("890126042XXXXXXXXXXX")
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
index 78a1838..59e3dff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
@@ -142,7 +142,9 @@
                     .when(phone).isUserDataEnabled();
         }
         mDataEvaluation = new DataEvaluation(DataEvaluation.DataEvaluationReason.EXTERNAL_QUERY);
-        doReturn(mDataEvaluation).when(mDataNetworkController).getInternetEvaluation(anyBoolean());
+        doReturn(mDataEvaluation).when(mDataNetworkController).evaluateNetworkRequest(
+                any(TelephonyNetworkRequest.class),
+                eq(DataEvaluation.DataEvaluationReason.EXTERNAL_QUERY));
         doReturn(new int[]{SUB_1, SUB_2}).when(mSubscriptionManagerService)
                 .getActiveSubIdList(true);
         doAnswer(invocation -> {
@@ -167,6 +169,8 @@
                 .getAutoDataSwitchAvailabilityStabilityTimeThreshold();
         doReturn(120000L).when(mDataConfigManager)
                 .getAutoDataSwitchPerformanceStabilityTimeThreshold();
+        doReturn(150000L).when(mDataConfigManager)
+                .getAutoDataSwitchAvailabilitySwitchbackStabilityTimeThreshold();
         doReturn(MAX_RETRY).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry();
         doReturn(SCORE_TOLERANCE).when(mDataConfigManager).getAutoDataSwitchScoreTolerance();
         doAnswer(invocation -> {
@@ -250,7 +254,9 @@
         mDataEvaluation.addDataDisallowedReason(DataEvaluation.DataDisallowedReason
                 .NO_SUITABLE_DATA_PROFILE);
         doReturn(mDataEvaluation)
-                .when(mDataNetworkController).getInternetEvaluation(anyBoolean());
+                .when(mDataNetworkController).evaluateNetworkRequest(
+                        any(TelephonyNetworkRequest.class),
+                        eq(DataEvaluation.DataEvaluationReason.EXTERNAL_QUERY));
         mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED);
         processAllFutureMessages();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
index 0695066..a6a4b0b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -166,7 +166,6 @@
         replaceInstance(SessionMetricsStats.class, "sInstance", null,
                 mMockSessionMetricsStats);
 
-        when(mFeatureFlags.satellitePersistentLogging()).thenReturn(true);
         when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         mDatagramDispatcherUT = new TestDatagramDispatcher(mContext, Looper.myLooper(),
                 mFeatureFlags,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
index a1f63d0..738a44e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -130,7 +130,6 @@
         replaceInstance(SessionMetricsStats.class, "sInstance", null,
                 mMockSessionMetricsStats);
 
-        when(mFeatureFlags.satellitePersistentLogging()).thenReturn(true);
         mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(), mFeatureFlags,
                 mMockDatagramController);
         mTestDemoModeDatagramReceiver = new TestDatagramReceiver(mContext, Looper.myLooper(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
index a228617..93af153 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
@@ -101,7 +101,6 @@
         super.setUp(getClass().getSimpleName());
         MockitoAnnotations.initMocks(this);
         logd(TAG + " Setup!");
-        when(mFeatureFlags.satellitePersistentLogging()).thenReturn(true);
         mInOrderForPointingUi = inOrder(mContext);
         replaceInstance(SatelliteModemInterface.class, "sInstance", null,
                 mMockSatelliteModemInterface);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
index 54cf227..65bfb83 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
@@ -153,7 +153,6 @@
         when(resources.getBoolean(
                  R.bool.config_satellite_allow_tn_scanning_during_satellite_session))
             .thenReturn(true);
-        when(mFeatureFlags.satellitePersistentLogging()).thenReturn(true);
         when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(false);
         when(mMockSatelliteController.isSatelliteRoamingP2pSmSSupported(
                 anyInt())).thenReturn(false);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index d44bd7b..4d4d160 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -118,7 +118,6 @@
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.UiccSlot;
 
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
 import org.junit.After;
@@ -450,51 +449,8 @@
     }
 
     @Test
-    @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
-    public void testSetPhoneNumber() {
-        doReturn(false).when(mFeatureFlags).enforceTelephonyFeatureMapping();
-        doReturn(true).when(mPackageManager).hasSystemFeature(
-                eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
-
-        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
-        mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1,
-                0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
-        processAllMessages();
-
-        verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1));
-        Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback);
-
-        // Caller does not have carrier privilege
-        assertThrows(SecurityException.class,
-                () -> mSubscriptionManagerServiceUT.setPhoneNumber(1,
-                        SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2,
-                        CALLING_PACKAGE, CALLING_FEATURE));
-
-        // Grant carrier privilege
-        setCarrierPrivilegesForSubId(true, 1);
-
-        // Source IMS is not acceptable
-        assertThrows(IllegalArgumentException.class,
-                () -> mSubscriptionManagerServiceUT.setPhoneNumber(1,
-                        SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, FAKE_PHONE_NUMBER2,
-                        CALLING_PACKAGE, CALLING_FEATURE));
-
-        mSubscriptionManagerServiceUT.setPhoneNumber(1,
-                SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2,
-                CALLING_PACKAGE, CALLING_FEATURE);
-        processAllMessages();
-
-        SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
-                .getSubscriptionInfoInternal(1);
-        assertThat(subInfo).isNotNull();
-        assertThat(subInfo.getNumberFromCarrier()).isEqualTo(FAKE_PHONE_NUMBER2);
-        verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1));
-    }
-
-    @Test
     @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
-    public void testSetPhoneNumber_EnabledEnforceTelephonyFeatureMappingForPublicApis()
-            throws Exception {
+    public void testSetPhoneNumber() throws Exception {
         mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
         mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1,
                 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
@@ -2520,10 +2476,12 @@
     }
 
     @Test
-    @DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
-    public void testGetPhoneNumber() {
+    @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
+    public void testGetPhoneNumber() throws Exception {
         mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
         testSetPhoneNumber();
+        doReturn(true).when(mPackageManager).hasSystemFeature(
+                eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
         assertThat(mSubscriptionManagerServiceUT.getPhoneNumber(1,
                 SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, CALLING_PACKAGE, CALLING_FEATURE))
                 .isEqualTo(FAKE_PHONE_NUMBER2);
@@ -2534,9 +2492,12 @@
     }
 
     @Test
-    public void testGetPhoneNumberFromUicc() {
+    @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
+    public void testGetPhoneNumberFromUicc() throws Exception {
         mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
         testSetPhoneNumber();
+        doReturn(true).when(mPackageManager).hasSystemFeature(
+                eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
         // Number from line1Number should be FAKE_PHONE_NUMBER1 instead of FAKE_PHONE_NUMBER2
         assertThat(mSubscriptionManagerServiceUT.getPhoneNumber(1,
                 SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, CALLING_PACKAGE, CALLING_FEATURE))