Merge "Add some extra config data used for validation" into 24D1-dev
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index e54c969..609bf7a 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -281,6 +281,7 @@
     optional bool is_iwlan_cross_sim_at_end = 38;
     optional bool is_iwlan_cross_sim_at_connected = 39;
     optional bool vonr_enabled = 40;
+    optional bool is_ntn = 41;
 
     // Internal use only
     optional int64 setup_begin_millis = 10001;
@@ -373,6 +374,7 @@
     repeated int32 handover_failure_rat = 21;
     optional bool is_non_dds = 22;
     optional bool is_iwlan_cross_sim = 23;
+    optional bool is_ntn = 24;
 }
 
 message CellularServiceState {
@@ -391,6 +393,7 @@
     optional bool override_voice_service = 13;
     optional bool isDataEnabled = 14;
     optional bool is_iwlan_cross_sim = 15;
+    optional bool is_ntn = 16;
 
     // Internal use only
     optional int64 last_used_millis = 10001;
@@ -662,6 +665,14 @@
     optional int32 satellite_service_initialization_result = 1;
     optional int32 satellite_technology = 2;
     optional int32 count = 3;
+    optional int32 satellite_service_termination_result = 4;
+    optional int64 initialization_processing_time_millis = 5;
+    optional int64 termination_processing_time_millis = 6;
+    optional int32 session_duration_seconds = 7;
+    optional int32 count_of_outgoing_datagram_success = 8;
+    optional int32 count_of_outgoing_datagram_failed = 9;
+    optional int32 count_of_incoming_datagram_success = 10;
+    optional int32 count_of_incoming_datagram_failed = 11;
 }
 
 message SatelliteIncomingDatagram {
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index f7c0cd6..2725295 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -1545,7 +1545,7 @@
             DataProfile emergencyProfile = mDataProfileManager.getDataProfileForNetworkRequest(
                     networkRequest, getDataNetworkType(transport),
                     mServiceState.isUsingNonTerrestrialNetwork(),
-                    isEsimBootStrapProvisioningActivated(), true);
+                    false /*isEsimBootStrapProvisioning*/, true);
 
             // Check if the profile is being throttled.
             if (mDataConfigManager.shouldHonorRetryTimerForEmergencyNetworkRequest()
@@ -1801,6 +1801,9 @@
 
             if (!TextUtils.isEmpty(subscriberId)) {
                 builder.setSubscriberIds(Set.of(subscriberId));
+                // Consider data usage calculation of only metered network.
+                // Emergency data usage is excluded.
+                builder.setMeteredness(android.net.NetworkStats.METERED_YES);
                 NetworkTemplate template = builder.build();
                 final NetworkStats.Bucket ret = networkStatsManager
                         .querySummaryForDevice(template, 0L, System.currentTimeMillis());
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index c4eb9ca..5c1d0e1 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -1562,6 +1562,9 @@
         mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID;
 
         if (subIdToValidate == mPreferredDataSubId.get()) {
+            if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+                mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+            }
             sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
             return;
         }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 1021ecf..b7c3255 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -1555,6 +1555,11 @@
 
                 @Override
                 public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
+                    if (!Objects.equals(mOngoingConnection, expectedConnection)) {
+                        Rlog.i(TAG, "isOkToCall "
+                                + expectedConnection.getTelecomCallId() + " canceled.");
+                        return true;
+                    }
                     // Wait for normal service state or timeout if required.
                     if (phone == phoneForEmergency
                             && waitForInServiceTimeout > 0
@@ -1567,6 +1572,11 @@
 
                 @Override
                 public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
+                    if (!Objects.equals(mOngoingConnection, expectedConnection)) {
+                        Rlog.i(TAG, "onTimeout "
+                                + expectedConnection.getTelecomCallId() + " canceled.");
+                        return true;
+                    }
                     // onTimeout shall be called only with the Phone for emergency
                     return phone.getServiceStateTracker().isRadioOn()
                             && !satelliteController.isSatelliteEnabled();
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index e1f6309..2eadf17 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.data.DataNetwork;
 import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.telephony.Rlog;
@@ -64,10 +65,12 @@
     public static final int SIZE_LIMIT_HANDOVER_FAILURES = 15;
 
     private final DefaultNetworkMonitor mDefaultNetworkMonitor;
+    private final SatelliteController mSatelliteController;
 
     public DataCallSessionStats(Phone phone) {
         mPhone = phone;
         mDefaultNetworkMonitor = PhoneFactory.getMetricsCollector().getDefaultNetworkMonitor();
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     private boolean isSystemDefaultNetworkMobile() {
@@ -303,6 +306,7 @@
                 call.handoverFailureRat.length);
         copy.isNonDds = call.isNonDds;
         copy.isIwlanCrossSim = call.isIwlanCrossSim;
+        copy.isNtn = call.isNtn;
         return copy;
     }
 
@@ -329,6 +333,8 @@
         proto.handoverFailureRat = new int[0];
         proto.isNonDds = false;
         proto.isIwlanCrossSim = false;
+        proto.isNtn = mSatelliteController != null
+                ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
         return proto;
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 456b91b..6aeb2fc 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -972,7 +972,8 @@
                 state.foldState,
                 state.overrideVoiceService,
                 state.isDataEnabled,
-                state.isIwlanCrossSim);
+                state.isIwlanCrossSim,
+                state.isNtn);
     }
 
     private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
@@ -1030,7 +1031,8 @@
                 session.isIwlanCrossSimAtStart,
                 session.isIwlanCrossSimAtEnd,
                 session.isIwlanCrossSimAtConnected,
-                session.vonrEnabled);
+                session.vonrEnabled,
+                session.isNtn);
 
     }
 
@@ -1107,7 +1109,8 @@
                 dataCallSession.handoverFailureCauses,
                 dataCallSession.handoverFailureRat,
                 dataCallSession.isNonDds,
-                dataCallSession.isIwlanCrossSim);
+                dataCallSession.isIwlanCrossSim,
+                dataCallSession.isNtn);
     }
 
     private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
@@ -1350,7 +1353,15 @@
                 SATELLITE_SESSION,
                 satelliteSession.satelliteServiceInitializationResult,
                 satelliteSession.satelliteTechnology,
-                satelliteSession.count);
+                satelliteSession.count,
+                satelliteSession.satelliteServiceTerminationResult,
+                satelliteSession.initializationProcessingTimeMillis,
+                satelliteSession.terminationProcessingTimeMillis,
+                satelliteSession.sessionDurationSeconds,
+                satelliteSession.countOfOutgoingDatagramSuccess,
+                satelliteSession.countOfOutgoingDatagramFailed,
+                satelliteSession.countOfIncomingDatagramSuccess,
+                satelliteSession.countOfIncomingDatagramFailed);
     }
 
     private static StatsEvent buildStatsEvent(SatelliteIncomingDatagram stats) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index f3fe8fa..9b9afaa 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -1715,7 +1715,8 @@
                     && state.foldState == key.foldState
                     && state.overrideVoiceService == key.overrideVoiceService
                     && state.isDataEnabled == key.isDataEnabled
-                    && state.isIwlanCrossSim == key.isIwlanCrossSim) {
+                    && state.isIwlanCrossSim == key.isIwlanCrossSim
+                    && state.isNtn == key.isNtn) {
                 return state;
             }
         }
@@ -2057,7 +2058,17 @@
         for (SatelliteSession stats : mAtoms.satelliteSession) {
             if (stats.satelliteServiceInitializationResult
                     == key.satelliteServiceInitializationResult
-                    && stats.satelliteTechnology == key.satelliteTechnology) {
+                    && stats.satelliteTechnology == key.satelliteTechnology
+                    && stats.satelliteServiceTerminationResult
+                    == key.satelliteServiceTerminationResult
+                    && stats.initializationProcessingTimeMillis
+                    == key.initializationProcessingTimeMillis
+                    && stats.terminationProcessingTimeMillis == key.terminationProcessingTimeMillis
+                    && stats.sessionDurationSeconds == key.sessionDurationSeconds
+                    && stats.countOfOutgoingDatagramSuccess == key.countOfOutgoingDatagramSuccess
+                    && stats.countOfOutgoingDatagramFailed == key.countOfOutgoingDatagramFailed
+                    && stats.countOfIncomingDatagramSuccess == key.countOfIncomingDatagramSuccess
+                    && stats.countOfIncomingDatagramFailed == key.countOfIncomingDatagramFailed) {
                 return stats;
             }
         }
diff --git a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
index 55eee1a..b58e62a 100644
--- a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
+++ b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.metrics;
 
+import android.telephony.satellite.SatelliteManager;
+
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
 import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
@@ -385,11 +387,28 @@
     public class SatelliteSessionParams {
         private final int mSatelliteServiceInitializationResult;
         private final int mSatelliteTechnology;
+        private final int mTerminationResult;
+        private final long mInitializationProcessingTimeMillis;
+        private final long mTerminationProcessingTimeMillis;
+        private final int mSessionDurationSec;
+        private final int mCountOfOutgoingDatagramSuccess;
+        private final int mCountOfOutgoingDatagramFailed;
+        private final int mCountOfIncomingDatagramSuccess;
+        private final int mCountOfIncomingDatagramFailed;
 
         private SatelliteSessionParams(Builder builder) {
             this.mSatelliteServiceInitializationResult =
                     builder.mSatelliteServiceInitializationResult;
             this.mSatelliteTechnology = builder.mSatelliteTechnology;
+            this.mTerminationResult = builder.mTerminationResult;
+            this.mInitializationProcessingTimeMillis = builder.mInitializationProcessingTimeMillis;
+            this.mTerminationProcessingTimeMillis =
+                    builder.mTerminationProcessingTimeMillis;
+            this.mSessionDurationSec = builder.mSessionDurationSec;
+            this.mCountOfOutgoingDatagramSuccess = builder.mCountOfOutgoingDatagramSuccess;
+            this.mCountOfOutgoingDatagramFailed = builder.mCountOfOutgoingDatagramFailed;
+            this.mCountOfIncomingDatagramSuccess = builder.mCountOfIncomingDatagramSuccess;
+            this.mCountOfIncomingDatagramFailed = builder.mCountOfIncomingDatagramFailed;
         }
 
         public int getSatelliteServiceInitializationResult() {
@@ -400,12 +419,52 @@
             return mSatelliteTechnology;
         }
 
+        public int getTerminationResult() {
+            return mTerminationResult;
+        }
+
+        public long getInitializationProcessingTime() {
+            return mInitializationProcessingTimeMillis;
+        }
+
+        public long getTerminationProcessingTime() {
+            return mTerminationProcessingTimeMillis;
+        }
+
+        public int getSessionDuration() {
+            return mSessionDurationSec;
+        }
+
+        public int getCountOfOutgoingDatagramSuccess() {
+            return mCountOfOutgoingDatagramSuccess;
+        }
+
+        public int getCountOfOutgoingDatagramFailed() {
+            return mCountOfOutgoingDatagramFailed;
+        }
+
+        public int getCountOfIncomingDatagramSuccess() {
+            return mCountOfIncomingDatagramSuccess;
+        }
+
+        public int getCountOfIncomingDatagramFailed() {
+            return mCountOfIncomingDatagramFailed;
+        }
+
         /**
          * A builder class to create {@link SatelliteSessionParams} data structure class
          */
         public static class Builder {
             private int mSatelliteServiceInitializationResult = -1;
             private int mSatelliteTechnology = -1;
+            private int mTerminationResult = -1;
+            private long mInitializationProcessingTimeMillis = -1;
+            private long mTerminationProcessingTimeMillis = -1;
+            private int mSessionDurationSec = -1;
+            private int mCountOfOutgoingDatagramSuccess = -1;
+            private int mCountOfOutgoingDatagramFailed = -1;
+            private int mCountOfIncomingDatagramSuccess = -1;
+            private int mCountOfIncomingDatagramFailed = -1;
 
             /**
              * Sets satelliteServiceInitializationResult value of {@link SatelliteSession}
@@ -426,6 +485,55 @@
                 return this;
             }
 
+            /** Sets the satellite de-initialization result. */
+            public Builder setTerminationResult(
+                    @SatelliteManager.SatelliteResult int result) {
+                this.mTerminationResult = result;
+                return this;
+            }
+
+            /** Sets the satellite initialization processing time. */
+            public Builder setInitializationProcessingTime(long processingTime) {
+                this.mInitializationProcessingTimeMillis = processingTime;
+                return this;
+            }
+
+            /** Sets the satellite de-initialization processing time. */
+            public Builder setTerminationProcessingTime(long processingTime) {
+                this.mTerminationProcessingTimeMillis = processingTime;
+                return this;
+            }
+
+            /** Sets the total enabled time for the satellite session. */
+            public Builder setSessionDuration(int sessionDurationSec) {
+                this.mSessionDurationSec = sessionDurationSec;
+                return this;
+            }
+
+            /** Sets the total number of successful outgoing datagram transmission. */
+            public Builder setCountOfOutgoingDatagramSuccess(int countOfoutgoingDatagramSuccess) {
+                this.mCountOfOutgoingDatagramSuccess = countOfoutgoingDatagramSuccess;
+                return this;
+            }
+
+            /** Sets the total number of failed outgoing datagram transmission. */
+            public Builder setCountOfOutgoingDatagramFailed(int countOfoutgoingDatagramFailed) {
+                this.mCountOfOutgoingDatagramFailed = countOfoutgoingDatagramFailed;
+                return this;
+            }
+
+            /** Sets the total number of successful incoming datagram transmission. */
+            public Builder setCountOfIncomingDatagramSuccess(int countOfincomingDatagramSuccess) {
+                this.mCountOfIncomingDatagramSuccess = countOfincomingDatagramSuccess;
+                return this;
+            }
+
+            /** Sets the total number of failed incoming datagram transmission. */
+            public Builder setCountOfIncomingDatagramFailed(int countOfincomingDatagramFailed) {
+                this.mCountOfIncomingDatagramFailed = countOfincomingDatagramFailed;
+                return this;
+            }
+
             /**
              * Returns SessionParams, which contains whole component of
              * {@link SatelliteSession} atom
@@ -441,7 +549,14 @@
             return "SessionParams("
                     + ", satelliteServiceInitializationResult="
                     + mSatelliteServiceInitializationResult
-                    + ", satelliteTechnology=" + mSatelliteTechnology
+                    + ", TerminationResult=" + mTerminationResult
+                    + ", InitializationProcessingTimeMillis=" + mInitializationProcessingTimeMillis
+                    + ", TerminationProcessingTimeMillis=" + mTerminationProcessingTimeMillis
+                    + ", SessionDurationSec=" + mSessionDurationSec
+                    + ", CountOfOutgoingDatagramSuccess=" + mCountOfOutgoingDatagramSuccess
+                    + ", CountOfOutgoingDatagramFailed=" + mCountOfOutgoingDatagramFailed
+                    + ", CountOfIncomingDatagramSuccess=" + mCountOfIncomingDatagramSuccess
+                    + ", CountOfIncomingDatagramFailed=" + mCountOfIncomingDatagramFailed
                     + ")";
         }
     }
@@ -912,6 +1027,14 @@
                 param.getSatelliteServiceInitializationResult();
         proto.satelliteTechnology = param.getSatelliteTechnology();
         proto.count = 1;
+        proto.satelliteServiceTerminationResult = param.getTerminationResult();
+        proto.initializationProcessingTimeMillis = param.getInitializationProcessingTime();
+        proto.terminationProcessingTimeMillis = param.getTerminationProcessingTime();
+        proto.sessionDurationSeconds = param.getSessionDuration();
+        proto.countOfOutgoingDatagramSuccess = param.getCountOfIncomingDatagramSuccess();
+        proto.countOfOutgoingDatagramFailed = param.getCountOfOutgoingDatagramFailed();
+        proto.countOfIncomingDatagramSuccess = param.getCountOfIncomingDatagramSuccess();
+        proto.countOfIncomingDatagramFailed = param.getCountOfOutgoingDatagramFailed();
         mAtomsStorage.addSatelliteSessionStats(proto);
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index d400c22..ff90978 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -44,6 +44,7 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.telephony.Rlog;
 
 import java.util.Set;
@@ -61,12 +62,14 @@
     private final PersistAtomsStorage mStorage;
     private final DeviceStateHelper mDeviceStateHelper;
     private boolean mExistAnyConnectedInternetPdn;
+    private final SatelliteController mSatelliteController;
 
     public ServiceStateStats(Phone phone) {
         super(Runnable::run);
         mPhone = phone;
         mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage();
         mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper();
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     /** Finalizes the durations of the current service state segment. */
@@ -135,6 +138,8 @@
             newState.overrideVoiceService = mOverrideVoiceService.get();
             newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled();
             newState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone);
+            newState.isNtn = mSatelliteController != null
+                    ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
             TimestampedServiceState prevState =
                     mLastState.getAndSet(new TimestampedServiceState(newState, now));
             addServiceStateAndSwitch(
@@ -306,6 +311,7 @@
         copy.overrideVoiceService = state.overrideVoiceService;
         copy.isDataEnabled = state.isDataEnabled;
         copy.isIwlanCrossSim = state.isIwlanCrossSim;
+        copy.isNtn = state.isNtn;
         return copy;
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 9cf53c9..8be9e83 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -75,6 +75,7 @@
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.AudioCodec;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.telephony.Rlog;
 
@@ -171,11 +172,14 @@
     private final VonrHelper mVonrHelper =
             PhoneFactory.getMetricsCollector().getVonrHelper();
 
+    private final SatelliteController mSatelliteController;
+
     public VoiceCallSessionStats(int phoneId, Phone phone, @NonNull FeatureFlags featureFlags) {
         mPhoneId = phoneId;
         mPhone = phone;
         mFlags = featureFlags;
         DataConnectionStateTracker.getInstance(phoneId).start(phone);
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     /* CS calls */
@@ -570,6 +574,9 @@
             proto.vonrEnabled = mVonrHelper.getVonrEnabled(mPhone.getSubId());
         }
 
+        proto.isNtn = mSatelliteController != null
+                ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
+
         mAtomsStorage.addVoiceCallSession(proto);
 
         // merge RAT usages to PersistPullers when the call session ends (i.e. no more active calls)
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index 204fc8e..d4e97db 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.satellite;
 
 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
@@ -74,6 +75,8 @@
     @GuardedBy("mLock")
     private int mSendSubId;
     @GuardedBy("mLock")
+    private @SatelliteManager.DatagramType int mDatagramType = DATAGRAM_TYPE_UNKNOWN;
+    @GuardedBy("mLock")
     private @SatelliteManager.SatelliteDatagramTransferState int mSendDatagramTransferState =
             SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
     @GuardedBy("mLock")
@@ -229,21 +232,23 @@
      * @param sendPendingCount number of datagrams that are currently being sent
      * @param errorCode If datagram transfer failed, the reason for failure.
      */
-    public void updateSendStatus(int subId,
+    public void updateSendStatus(int subId, @SatelliteManager.DatagramType int datagramType,
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int sendPendingCount, int errorCode) {
         synchronized (mLock) {
             logd("updateSendStatus"
                     + " subId: " + subId
+                    + " datagramType: " + datagramType
                     + " datagramTransferState: " + datagramTransferState
                     + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode);
 
             mSendSubId = subId;
+            mDatagramType = datagramType;
             mSendDatagramTransferState = datagramTransferState;
             mSendPendingCount = sendPendingCount;
             mSendErrorCode = errorCode;
             notifyDatagramTransferStateChangedToSessionController();
-            mPointingAppController.updateSendDatagramTransferState(mSendSubId,
+            mPointingAppController.updateSendDatagramTransferState(mSendSubId, mDatagramType,
                     mSendDatagramTransferState, mSendPendingCount, mSendErrorCode);
             retryPollPendingDatagramsInDemoMode();
         }
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index 1f98168..7ead441 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
@@ -42,6 +43,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.metrics.SatelliteStats;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
+import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
 
 import java.util.LinkedHashMap;
 import java.util.Map.Entry;
@@ -69,6 +71,7 @@
     @NonNull private final Context mContext;
     @NonNull private final DatagramController mDatagramController;
     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
+    @NonNull private final SessionMetricsStats mSessionMetricsStats;
 
     private boolean mIsDemoMode = false;
     private boolean mIsAligned = false;
@@ -101,6 +104,8 @@
             mPendingNonEmergencyDatagramsMap = new LinkedHashMap<>();
 
     private long mWaitTimeForDatagramSendingResponse;
+    @SatelliteManager.DatagramType
+    private int mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
 
     /**
      * Create the DatagramDispatcher singleton instance.
@@ -131,6 +136,7 @@
         mContext = context;
         mDatagramController = datagramController;
         mControllerMetricsStats = ControllerMetricsStats.getInstance();
+        mSessionMetricsStats = SessionMetricsStats.getInstance();
 
         synchronized (mLock) {
             mSendingDatagramInProgress = false;
@@ -268,11 +274,12 @@
 
                     if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
                         // Update send status for current datagram
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
                                 getPendingDatagramCount(), error);
                         mControllerMetricsStats.reportOutgoingDatagramSuccessCount(
                                 argument.datagramType);
+                        mSessionMetricsStats.addCountOfSuccessfulOutgoingDatagram();
                         startWaitForSimulatedPollDatagramsDelayTimer(request);
                         if (getPendingDatagramCount() > 0) {
                             // Send response for current datagram
@@ -281,17 +288,18 @@
                             sendPendingDatagrams();
                         } else {
                             mDatagramController.updateSendStatus(argument.subId,
-                                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                                    0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                                    argument.datagramType,
+                                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
+                                    SatelliteManager.SATELLITE_RESULT_SUCCESS);
                             // Send response for current datagram
                             argument.callback.accept(error);
                         }
                     } else {
                         // Update send status
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                                 getPendingDatagramCount(), error);
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                                 0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
                         // Send response for current datagram
@@ -300,6 +308,7 @@
                         // Abort sending all the pending datagrams
                         mControllerMetricsStats.reportOutgoingDatagramFailCount(
                                 argument.datagramType);
+                        mSessionMetricsStats.addCountOfFailedOutgoingDatagram();
                         abortSendingPendingDatagrams(argument.subId,
                                 SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
                     }
@@ -318,7 +327,8 @@
             }
 
             case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT:
-                handleEventDatagramWaitForConnectedStateTimedOut();
+                handleEventDatagramWaitForConnectedStateTimedOut(
+                        (SendSatelliteDatagramArgument) msg.obj);
                 break;
 
             case EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT:
@@ -356,10 +366,10 @@
 
         long datagramId = mNextDatagramId.getAndUpdate(
                 n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID));
-
         SendSatelliteDatagramArgument datagramArgs =
                 new SendSatelliteDatagramArgument(subId, datagramId, datagramType, datagram,
                         needFullScreenPointingUI, callback);
+        mLastSendRequestDatagramType = datagramType;
 
         synchronized (mLock) {
             // Add datagram to pending datagram map
@@ -371,16 +381,16 @@
 
             if (mDatagramController.needsWaitingForSatelliteConnected()) {
                 logd("sendDatagram: wait for satellite connected");
-                mDatagramController.updateSendStatus(subId,
+                mDatagramController.updateSendStatus(subId, datagramType,
                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
                         getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
-                startDatagramWaitForConnectedStateTimer();
+                startDatagramWaitForConnectedStateTimer(datagramArgs);
             } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) {
                 // Modem can be busy receiving datagrams, so send datagram only when modem is
                 // not busy.
                 mSendingDatagramInProgress = true;
                 datagramArgs.setDatagramStartTime();
-                mDatagramController.updateSendStatus(subId,
+                mDatagramController.updateSendStatus(subId, datagramType,
                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
                         getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
                 sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone);
@@ -508,7 +518,7 @@
                     pendingDatagram.iterator().next().getValue();
             // Sets the trigger time for getting pending datagrams
             datagramArg.setDatagramStartTime();
-            mDatagramController.updateSendStatus(datagramArg.subId,
+            mDatagramController.updateSendStatus(datagramArg.subId, datagramArg.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
                     getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
             sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone);
@@ -588,8 +598,10 @@
                         .setDatagramType(argument.datagramType)
                         .setResultCode(resultCode)
                         .setDatagramSizeBytes(argument.getDatagramRoundedSizeBytes())
-                        .setDatagramTransferTimeMillis(
-                                System.currentTimeMillis() - argument.datagramStartTime)
+                        /* In case pending datagram has not been attempted to send to modem
+                        interface. transfer time will be 0. */
+                        .setDatagramTransferTimeMillis(argument.datagramStartTime > 0
+                                ? (System.currentTimeMillis() - argument.datagramStartTime) : 0)
                         .build());
     }
 
@@ -630,12 +642,13 @@
         logd("cleanUpResources");
         mSendingDatagramInProgress = false;
         if (getPendingDatagramCount() > 0) {
-            mDatagramController.updateSendStatus(
-                    SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    mLastSendRequestDatagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
         }
         mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                mLastSendRequestDatagramType,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                 0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
         abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
@@ -648,15 +661,17 @@
         mIsDemoMode = false;
         mSendSatelliteDatagramRequest = null;
         mIsAligned = false;
+        mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
     }
 
-    private void startDatagramWaitForConnectedStateTimer() {
+    private void startDatagramWaitForConnectedStateTimer(
+            @NonNull SendSatelliteDatagramArgument datagramArgs) {
         if (isDatagramWaitForConnectedStateTimerStarted()) {
             logd("DatagramWaitForConnectedStateTimer is already started");
             return;
         }
         sendMessageDelayed(obtainMessage(
-                        EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT),
+                        EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT, datagramArgs),
                 mDatagramController.getDatagramWaitTimeForConnectedState());
     }
 
@@ -695,19 +710,24 @@
         removeMessages(EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT);
     }
 
-    private void handleEventDatagramWaitForConnectedStateTimedOut() {
+    private void handleEventDatagramWaitForConnectedStateTimedOut(
+            @NonNull SendSatelliteDatagramArgument argument) {
         logw("Timed out to wait for satellite connected before sending datagrams");
         synchronized (mLock) {
             // Update send status
             mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(),
                     SATELLITE_RESULT_NOT_REACHABLE);
             mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
             abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                     SATELLITE_RESULT_NOT_REACHABLE);
+            mControllerMetricsStats.reportOutgoingDatagramFailCount(argument.datagramType);
+            mSessionMetricsStats.addCountOfFailedOutgoingDatagram();
         }
     }
 
@@ -757,10 +777,10 @@
             mSendingDatagramInProgress = false;
 
             // Update send status
-            mDatagramController.updateSendStatus(argument.subId,
+            mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(), SATELLITE_RESULT_MODEM_TIMEOUT);
-            mDatagramController.updateSendStatus(argument.subId,
+            mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
 
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index a4b1193..94b4bd3 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.satellite;
 
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
 
@@ -51,6 +52,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.metrics.SatelliteStats;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
+import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
 import com.android.internal.util.FunctionalUtils;
 
 import java.util.concurrent.ConcurrentHashMap;
@@ -79,6 +81,7 @@
     @NonNull private SharedPreferences mSharedPreferences = null;
     @NonNull private final DatagramController mDatagramController;
     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
+    @NonNull private final SessionMetricsStats mSessionMetricsStats;
     @NonNull private final Looper mLooper;
 
     private long mDatagramTransferStartTime = 0;
@@ -137,6 +140,7 @@
         mContentResolver = context.getContentResolver();
         mDatagramController = datagramController;
         mControllerMetricsStats = ControllerMetricsStats.getInstance();
+        mSessionMetricsStats = SessionMetricsStats.getInstance();
 
         try {
             mSharedPreferences =
@@ -354,9 +358,6 @@
                                     obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM,
                                             argument), getTimeoutToReceiveAck());
                         });
-
-                        sInstance.mControllerMetricsStats.reportIncomingDatagramCount(
-                                SatelliteManager.SATELLITE_RESULT_SUCCESS);
                     }
 
                     if (pendingCount <= 0) {
@@ -377,8 +378,8 @@
                     }
 
                     // Send the captured data about incoming datagram to metric
-                    sInstance.reportMetrics(
-                            satelliteDatagram, SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                    sInstance.reportMetrics(satelliteDatagram,
+                            SatelliteManager.SATELLITE_RESULT_SUCCESS);
                     break;
                 }
 
@@ -468,7 +469,6 @@
                             SatelliteManager.SATELLITE_RESULT_SUCCESS);
 
                     reportMetrics(null, error);
-                    mControllerMetricsStats.reportIncomingDatagramCount(error);
                 }
                 // Send response for current request
                 ((Consumer<Integer>) request.argument).accept(error);
@@ -712,7 +712,7 @@
     private void reportMetrics(@Nullable SatelliteDatagram satelliteDatagram,
             @NonNull @SatelliteManager.SatelliteResult int resultCode) {
         int datagramSizeRoundedBytes = -1;
-        int datagramTransferTime = 0;
+        long datagramTransferTime = 0;
 
         if (satelliteDatagram != null) {
             if (satelliteDatagram.getSatelliteDatagram() != null) {
@@ -721,7 +721,7 @@
                 datagramSizeRoundedBytes =
                         (int) (Math.round((double) sizeBytes / ROUNDING_UNIT) * ROUNDING_UNIT);
             }
-            datagramTransferTime = (int) (System.currentTimeMillis() - mDatagramTransferStartTime);
+            datagramTransferTime = (System.currentTimeMillis() - mDatagramTransferStartTime);
             mDatagramTransferStartTime = 0;
         }
 
@@ -731,6 +731,13 @@
                         .setDatagramSizeBytes(datagramSizeRoundedBytes)
                         .setDatagramTransferTimeMillis(datagramTransferTime)
                         .build());
+
+        mControllerMetricsStats.reportIncomingDatagramCount(resultCode);
+        if (resultCode == SATELLITE_RESULT_SUCCESS) {
+            mSessionMetricsStats.addCountOfSuccessfulIncomingDatagram();
+        } else {
+            mSessionMetricsStats.addCountOfFailedIncomingDatagram();
+        }
     }
 
     /** Set demo mode
@@ -841,8 +848,6 @@
                     SatelliteManager.SATELLITE_RESULT_SUCCESS);
 
             reportMetrics(null, SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
-            mControllerMetricsStats.reportIncomingDatagramCount(
-                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
 
             Consumer<Integer> callback =
                     (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument;
diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
index 878ee96..5e79a06 100644
--- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java
+++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
@@ -160,12 +160,14 @@
     }
 
     private static final class DatagramTransferStateHandlerRequest {
+        public int datagramType;
         public int datagramTransferState;
         public int pendingCount;
         public int errorCode;
 
-        DatagramTransferStateHandlerRequest(int datagramTransferState, int pendingCount,
-                int errorCode) {
+        DatagramTransferStateHandlerRequest(int datagramType, int datagramTransferState,
+                int pendingCount, int errorCode) {
+            this.datagramType = datagramType;
             this.datagramTransferState = datagramTransferState;
             this.pendingCount = pendingCount;
             this.errorCode = errorCode;
@@ -232,8 +234,9 @@
                     List<IBinder> toBeRemoved = new ArrayList<>();
                     mListeners.values().forEach(listener -> {
                         try {
-                            listener.onSendDatagramStateChanged(request.datagramTransferState,
-                                    request.pendingCount, request.errorCode);
+                            listener.onSendDatagramStateChanged(request.datagramType,
+                                    request.datagramTransferState, request.pendingCount,
+                                    request.errorCode);
                         } catch (RemoteException e) {
                             logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e);
                             toBeRemoved.add(listener.asBinder());
@@ -403,10 +406,11 @@
     }
 
     public void updateSendDatagramTransferState(int subId,
+            @SatelliteManager.DatagramType int datagramType,
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int sendPendingCount, int errorCode) {
         DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest(
-                datagramTransferState, sendPendingCount, errorCode);
+                datagramType, datagramTransferState, sendPendingCount, errorCode);
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
 
@@ -424,7 +428,8 @@
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int receivePendingCount, int errorCode) {
         DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest(
-                datagramTransferState, receivePendingCount, errorCode);
+                SatelliteManager.DATAGRAM_TYPE_UNKNOWN, datagramTransferState, receivePendingCount,
+                errorCode);
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
 
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index cf8dfac..2d28c9c 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -17,7 +17,10 @@
 package com.android.internal.telephony.satellite;
 
 import static android.provider.Settings.ACTION_SATELLITE_SETTING;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY;
 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_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;
@@ -128,14 +131,15 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Satellite controller is the backend service of
@@ -163,6 +167,9 @@
     private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY =
             "oem_enabled_satellite_provision_status_key";
 
+    public static final long DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS =
+            TimeUnit.SECONDS.toMillis(30);
+
     /** Message codes used in handleMessage() */
     //TODO: Move the Commands and events related to position updates to PointingAppController
     private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1;
@@ -211,6 +218,7 @@
     @NonNull private final DatagramController mDatagramController;
     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
     @NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
+    @NonNull private SessionMetricsStats mSessionMetricsStats;
     @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
     private final CommandsInterface mCi;
     private ContentResolver mContentResolver;
@@ -404,6 +412,9 @@
     private final BTWifiNFCStateReceiver mBTWifiNFCSateReceiver;
     private final UwbAdapterStateCallback mUwbAdapterStateCallback;
 
+    private long mSessionStartTimeStamp;
+    private long mSessionProcessingTimeStamp;
+
     /**
      * @return The singleton instance of SatelliteController.
      */
@@ -457,6 +468,7 @@
         // should be called before making DatagramController
         mControllerMetricsStats = ControllerMetricsStats.make(mContext);
         mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance();
+        mSessionMetricsStats = SessionMetricsStats.getInstance();
         mSubscriptionManagerService = SubscriptionManagerService.getInstance();
 
         // Create the DatagramController singleton,
@@ -998,18 +1010,31 @@
                 }
 
                 if (argument.enableSatellite) {
+                    mSessionMetricsStats.setInitializationResult(error)
+                            .setSatelliteTechnology(getSupportedNtnRadioTechnology())
+                            .setInitializationProcessingTime(
+                                    System.currentTimeMillis() - mSessionProcessingTimeStamp);
+                    mSessionProcessingTimeStamp = 0;
+
                     if (error == SATELLITE_RESULT_SUCCESS) {
                         mControllerMetricsStats.onSatelliteEnabled();
                         mControllerMetricsStats.reportServiceEnablementSuccessCount();
                     } else {
+                        mSessionMetricsStats.reportSessionMetrics();
+                        mSessionStartTimeStamp = 0;
                         mControllerMetricsStats.reportServiceEnablementFailCount();
                     }
-                    SessionMetricsStats.getInstance()
-                            .setInitializationResult(error)
-                            .setRadioTechnology(getSupportedNtnRadioTechnology())
-                            .reportSessionMetrics();
                 } else {
+                    mSessionMetricsStats.setTerminationResult(error)
+                            .setTerminationProcessingTime(System.currentTimeMillis()
+                                    - mSessionProcessingTimeStamp)
+                            .setSessionDurationSec(calculateSessionDurationTimeSec())
+                            .reportSessionMetrics();
+                    mSessionStartTimeStamp = 0;
+                    mSessionProcessingTimeStamp = 0;
+
                     mControllerMetricsStats.onSatelliteDisabled();
+
                     synchronized (mIsSatelliteEnabledLock) {
                         mWaitingForDisableSatelliteModemResponse = false;
                     }
@@ -2575,7 +2600,22 @@
                 loge("getSupportedSatelliteServices: mSatelliteServicesSupportedByCarriers does "
                         + "not contain key subId=" + subId);
             }
-            return new ArrayList<>();
+
+            /* Returns default capabilities when carrier config does not contain service
+               capabilities for the given plmn */
+            PersistableBundle config = getPersistableBundle(subId);
+            int [] defaultCapabilities = config.getIntArray(
+                    KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY);
+            if (defaultCapabilities == null) {
+                logd("getSupportedSatelliteServices: defaultCapabilities is null");
+                return new ArrayList<>();
+            }
+            List<Integer> capabilitiesList = Arrays.stream(
+                    defaultCapabilities).boxed().collect(Collectors.toList());
+            logd("getSupportedSatelliteServices: subId=" + subId
+                    + ", supportedServices does not contain key plmn=" + plmn
+                    + ", return default values " + capabilitiesList);
+            return capabilitiesList;
         }
     }
 
@@ -2622,6 +2662,32 @@
     }
 
     /**
+     * @return {@code true} if satellite emergency messaging is supported via carrier by any
+     * subscription on the device, {@code false} otherwise.
+     */
+    public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
+        if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("isSatelliteEmergencyMessagingSupportedViaCarrier: carrierEnabledSatelliteFlag is"
+                    + " disabled");
+            return false;
+        }
+        for (Phone phone : PhoneFactory.getPhones()) {
+            if (isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isSatelliteEmergencyMessagingSupportedViaCarrier(int subId) {
+        if (!isSatelliteSupportedViaCarrier(subId)) {
+            return false;
+        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return config.getBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL);
+    }
+
+    /**
      * @return {@code Pair<true, subscription ID>} if any subscription on the device is connected to
      * satellite, {@code Pair<false, null>} otherwise.
      */
@@ -2740,6 +2806,38 @@
         return new ArrayList<>();
     }
 
+    /**
+     * Get the carrier-enabled emergency call wait for connection timeout millis
+     */
+    public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+        long maxTimeoutMillis = 0;
+        for (Phone phone : PhoneFactory.getPhones()) {
+            if (!isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
+                continue;
+            }
+
+            int timeoutMillis =
+                    getCarrierEmergencyCallWaitForConnectionTimeoutMillis(phone.getSubId());
+            // Prioritize getting the timeout duration from the phone that is in satellite mode
+            // with carrier roaming
+            if (isInSatelliteModeForCarrierRoaming(phone)) {
+                return timeoutMillis;
+            }
+            if (maxTimeoutMillis < timeoutMillis) {
+                maxTimeoutMillis = timeoutMillis;
+            }
+        }
+        if (maxTimeoutMillis != 0) {
+            return maxTimeoutMillis;
+        }
+        return DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
+    }
+
+    private int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
+        PersistableBundle config = getPersistableBundle(subId);
+        return config.getInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected long getElapsedRealtime() {
         return SystemClock.elapsedRealtime();
@@ -2886,6 +2984,10 @@
         } else {
             callback.accept(result);
         }
+        mProvisionMetricsStats.setResultCode(result)
+                .setIsProvisionRequest(true)
+                .reportProvisionMetrics();
+        mControllerMetricsStats.reportProvisionCount(result);
     }
 
     private void handleEventDeprovisionSatelliteServiceDone(
@@ -3023,6 +3125,12 @@
         mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
                 argument.enableDemoMode, argument.isEmergency, onCompleted);
         startWaitForSatelliteEnablingResponseTimer(argument);
+        // Logs satellite session timestamps for session metrics
+        if (argument.enableSatellite) {
+            mSessionStartTimeStamp = System.currentTimeMillis();
+        }
+        mSessionProcessingTimeStamp = System.currentTimeMillis();
+
     }
 
     private void handleRequestSatelliteAttachRestrictionForCarrierCmd(
@@ -3477,7 +3585,8 @@
                 }
             }
 
-            if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) {
+            if (mSatelliteServicesSupportedByCarriers.containsKey(subId)
+                    && mSatelliteServicesSupportedByCarriers.get(subId) != null) {
                 carrierPlmnList =
                         mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList();
                 logd("mMergedPlmnListPerCarrier is updated by carrier config: "
@@ -3533,16 +3642,10 @@
 
     @NonNull
     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) {
-        synchronized (mCarrierConfigArrayLock) {
-            PersistableBundle config = mCarrierConfigArray.get(subId);
-            if (config == null) {
-                config = getConfigForSubId(subId);
-                mCarrierConfigArray.put(subId, config);
-            }
-            return SatelliteServiceUtils.parseSupportedSatelliteServices(
-                    config.getPersistableBundle(
-                            KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
-        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return SatelliteServiceUtils.parseSupportedSatelliteServices(
+                config.getPersistableBundle(
+                        KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
     }
 
     @NonNull private PersistableBundle getConfigForSubId(int subId) {
@@ -3550,7 +3653,10 @@
                 KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
                 KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT,
-                KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL);
+                KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
+                KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
+                KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
         if (config == null || config.isEmpty()) {
             config = CarrierConfigManager.getDefaultConfig();
         }
@@ -3929,10 +4035,11 @@
     private void sendErrorAndReportSessionMetrics(@SatelliteManager.SatelliteResult int error,
             Consumer<Integer> result) {
         result.accept(error);
-        SessionMetricsStats.getInstance()
-                .setInitializationResult(error)
-                .setRadioTechnology(getSupportedNtnRadioTechnology())
+        mSessionMetricsStats.setInitializationResult(error)
+                .setSatelliteTechnology(getSupportedNtnRadioTechnology())
                 .reportSessionMetrics();
+        mSessionStartTimeStamp = 0;
+        mSessionProcessingTimeStamp = 0;
     }
 
     private void registerForServiceStateChanged() {
@@ -3983,15 +4090,9 @@
     }
 
     private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
-        synchronized (mCarrierConfigArrayLock) {
-            PersistableBundle config = mCarrierConfigArray.get(subId);
-            if (config == null) {
-                config = getConfigForSubId(subId);
-                mCarrierConfigArray.put(subId, config);
-            }
-            return (config.getInt(
-                    KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
-        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return (config.getInt(
+                KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
     }
 
     private void persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned) {
@@ -4148,10 +4249,13 @@
                     sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
                 }
                 mControllerMetricsStats.reportServiceEnablementFailCount();
-                SessionMetricsStats.getInstance()
-                        .setInitializationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
-                        .setRadioTechnology(getSupportedNtnRadioTechnology())
+                mSessionMetricsStats.setInitializationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
+                        .setSatelliteTechnology(getSupportedNtnRadioTechnology())
+                        .setInitializationProcessingTime(
+                                System.currentTimeMillis() - mSessionProcessingTimeStamp)
                         .reportSessionMetrics();
+                mSessionStartTimeStamp = 0;
+                mSessionProcessingTimeStamp = 0;
             } else {
                 /*
                  * Unregister Importance Listener for Pointing UI when Satellite is disabled
@@ -4165,6 +4269,14 @@
                 mControllerMetricsStats.onSatelliteDisabled();
                 mWaitingForDisableSatelliteModemResponse = false;
                 mWaitingForSatelliteModemOff = false;
+                mSessionMetricsStats.setTerminationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
+                        .setSatelliteTechnology(getSupportedNtnRadioTechnology())
+                        .setTerminationProcessingTime(
+                                System.currentTimeMillis() - mSessionProcessingTimeStamp)
+                        .setSessionDurationSec(calculateSessionDurationTimeSec())
+                        .reportSessionMetrics();
+                mSessionStartTimeStamp = 0;
+                mSessionProcessingTimeStamp = 0;
             }
         }
     }
@@ -4333,6 +4445,26 @@
                 notificationBuilder.build(), UserHandle.ALL);
     }
 
+    @NonNull
+    private PersistableBundle getPersistableBundle(int subId) {
+        synchronized (mCarrierConfigArrayLock) {
+            PersistableBundle config = mCarrierConfigArray.get(subId);
+            if (config == null) {
+                config = getConfigForSubId(subId);
+                mCarrierConfigArray.put(subId, config);
+            }
+            return config;
+        }
+    }
+
+    // Should be invoked only when session termination done or session termination failed.
+    private int calculateSessionDurationTimeSec() {
+        return (int) (
+                (System.currentTimeMillis() - mSessionStartTimeStamp
+                - mSessionMetricsStats.getSessionInitializationProcessingTimeMillis()
+                - mSessionMetricsStats.getSessionTerminationProcessingTimeMillis()) / 1000);
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index c491476..9e9f9d7 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -99,7 +100,8 @@
     private boolean mIsSatelliteAllowedForCurrentLocation = false;
     @GuardedBy("mLock")
     private boolean mCheckingAccessRestrictionInProgress = false;
-    private final long mTimeoutMillis;
+    protected long mTimeoutMillis = 0;
+    private final long mOemEnabledTimeoutMillis;
     private final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime =
             new AtomicBoolean(false);
     @GuardedBy("mLock")
@@ -114,8 +116,7 @@
      * @param looper The looper used with the handler of this class.
      */
     public SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper) {
-        this(context, looper, SatelliteController.getInstance(), null,
-                getEmergencyCallWaitForConnectionTimeoutMillis(context));
+        this(context, looper, SatelliteController.getInstance(), null);
     }
 
     /**
@@ -127,17 +128,16 @@
      * @param satelliteController The SatelliteController singleton instance.
      * @param imsManager The ImsManager instance associated with the phone, which is used for making
      *                   the emergency call. This argument is not null only in unit tests.
-     * @param timeoutMillis The timeout duration of the timer.
      */
     @VisibleForTesting
     protected SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper,
-            @NonNull SatelliteController satelliteController, ImsManager imsManager,
-            long timeoutMillis) {
+            @NonNull SatelliteController satelliteController, ImsManager imsManager) {
         super(looper);
         mContext = context;
         mSatelliteController = satelliteController;
         mImsManager = imsManager;
-        mTimeoutMillis = timeoutMillis;
+        mOemEnabledTimeoutMillis =
+                getOemEnabledEmergencyCallWaitForConnectionTimeoutMillis(context);
         mISatelliteProvisionStateCallback = new ISatelliteProvisionStateCallback.Stub() {
             @Override
             public void onSatelliteProvisionStateChanged(boolean provisioned) {
@@ -185,7 +185,7 @@
      */
     public void onEmergencyCallStarted(@NonNull Connection connection) {
         if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
+                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
             logd("onEmergencyCallStarted: satellite is not supported");
             return;
         }
@@ -212,7 +212,7 @@
             String callId, @Connection.ConnectionState int state) {
         logd("callId=" + callId + ", state=" + state);
         if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
+                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
             logd("onEmergencyCallConnectionStateChanged: satellite is not supported");
             return;
         }
@@ -222,13 +222,15 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected ComponentName getDefaultSmsApp() {
-        return SmsApplication.getDefaultSmsApplication(mContext, false);
+        return SmsApplication.getDefaultSendToApplication(mContext, false);
     }
 
     private void handleEmergencyCallStartedEvent(@NonNull Connection connection) {
         if (sendEventDisplayEmergencyMessageForcefully(connection)) {
             return;
         }
+
+        selectEmergencyCallWaitForConnectionTimeoutDuration();
         if (mEmergencyConnection == null) {
             handleStateChangedEventForHysteresisTimer();
             registerForInterestedStateChangedEvents();
@@ -504,7 +506,18 @@
         }
     }
 
-    private static long getEmergencyCallWaitForConnectionTimeoutMillis(@NonNull Context context) {
+    private void selectEmergencyCallWaitForConnectionTimeoutDuration() {
+        if (mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
+            mTimeoutMillis =
+                    mSatelliteController.getCarrierEmergencyCallWaitForConnectionTimeoutMillis();
+        } else {
+            mTimeoutMillis = mOemEnabledTimeoutMillis;
+        }
+        logd("mTimeoutMillis = " + mTimeoutMillis);
+    }
+
+    private static long getOemEnabledEmergencyCallWaitForConnectionTimeoutMillis(
+            @NonNull Context context) {
         return context.getResources().getInteger(
                 R.integer.config_emergency_call_wait_for_connection_timeout_millis);
     }
@@ -615,14 +628,27 @@
         result.putInt(EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE, handoverType);
         if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
             result.putParcelable(EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT,
-                    createHandoverAppLaunchPendingIntent(packageName, className, action));
+                    createHandoverAppLaunchPendingIntent(
+                            handoverType, packageName, className, action));
         }
         return result;
     }
 
-    @NonNull private PendingIntent createHandoverAppLaunchPendingIntent(
+    @NonNull private PendingIntent createHandoverAppLaunchPendingIntent(int handoverType,
             @NonNull String packageName, @NonNull String className, @Nullable String action) {
-        Intent intent = new Intent(action);
+        Intent intent;
+        if (handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911) {
+            String emergencyNumber = "911";
+            if (mEmergencyConnection != null) {
+                emergencyNumber = mEmergencyConnection.getAddress().getSchemeSpecificPart();
+            }
+            logd("emergencyNumber=" + emergencyNumber);
+
+            Uri uri = Uri.parse("smsto:" + emergencyNumber);
+            intent = new Intent(Intent.ACTION_SENDTO, uri);
+        } else {
+            intent = new Intent(action);
+        }
         intent.setComponent(new ComponentName(packageName, className));
         return PendingIntent.getActivity(mContext, 0, intent,
                 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
@@ -649,8 +675,10 @@
     private void handleCmdSendEventDisplayEmergencyMessageForcefully(
             @NonNull Connection connection) {
         logd("Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer forcefully.");
+        mEmergencyConnection = connection;
         Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
         connection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
+        mEmergencyConnection = null;
     }
 
     private boolean isMultiSim() {
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java
index d48c488..0647231 100644
--- a/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java
+++ b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java
@@ -91,7 +91,7 @@
                         .setIsCanceled(mIsCanceled)
                         .build();
         SatelliteStats.getInstance().onSatelliteProvisionMetrics(provisionParams);
-        logd(provisionParams.toString());
+        logd("reportProvisionMetrics: " + provisionParams.toString());
         initializeProvisionParams();
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java
index 6585bec..2effd89 100644
--- a/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java
+++ b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java
@@ -32,6 +32,15 @@
     private static SessionMetricsStats sInstance = null;
     private @SatelliteManager.SatelliteResult int mInitializationResult;
     private @SatelliteManager.NTRadioTechnology int mRadioTechnology;
+    private @SatelliteManager.SatelliteResult int mTerminationResult;
+    private long mInitializationProcessingTimeMillis;
+    private long mTerminationProcessingTimeMillis;
+    private int mSessionDurationSec;
+    private int mCountOfSuccessfulOutgoingDatagram;
+    private int mCountOfFailedOutgoingDatagram;
+    private int mCountOfSuccessfulIncomingDatagram;
+    private int mCountOfIncomingDatagramFailed;
+
 
     private SessionMetricsStats() {
         initializeSessionMetricsParam();
@@ -42,7 +51,7 @@
      * If an instance of the Singleton class has not been created,
      * it creates a new instance and returns it. Otherwise, it returns
      * the existing instance.
-     * @return the Singleton instance of SessionMetricsStats
+     * @return the Singleton instance of SessionMetricsStats.
      */
     public static SessionMetricsStats getInstance() {
         if (sInstance == null) {
@@ -52,7 +61,7 @@
         return sInstance;
     }
 
-    /** Sets the satellite initialization result */
+    /** Sets the satellite initialization result. */
     public SessionMetricsStats setInitializationResult(
             @SatelliteManager.SatelliteResult int result) {
         logd("setInitializationResult(" + result + ")");
@@ -60,29 +69,114 @@
         return this;
     }
 
-    /** Sets the satellite ratio technology */
-    public SessionMetricsStats setRadioTechnology(
+    /** Sets the satellite ratio technology. */
+    public SessionMetricsStats setSatelliteTechnology(
             @SatelliteManager.NTRadioTechnology int radioTechnology) {
-        logd("setRadioTechnology(" + radioTechnology + ")");
+        logd("setSatelliteTechnology(" + radioTechnology + ")");
         mRadioTechnology = radioTechnology;
         return this;
     }
 
-    /** Report the session metrics atoms to PersistAtomsStorage in telephony */
+    /** Sets the satellite de-initialization result. */
+    public SessionMetricsStats setTerminationResult(
+            @SatelliteManager.SatelliteResult int result) {
+        logd("setTerminationResult(" + result + ")");
+        mTerminationResult = result;
+        return this;
+    }
+
+    /** Sets the satellite initialization processing time. */
+    public SessionMetricsStats setInitializationProcessingTime(long processingTime) {
+        logd("setInitializationProcessingTime(" + processingTime + ")");
+        mInitializationProcessingTimeMillis = processingTime;
+        return this;
+    }
+
+    /** Sets the satellite de-initialization processing time. */
+    public SessionMetricsStats setTerminationProcessingTime(long processingTime) {
+        logd("setTerminationProcessingTime(" + processingTime + ")");
+        mTerminationProcessingTimeMillis = processingTime;
+        return this;
+    }
+
+    /** Sets the total enabled time for the satellite session. */
+    public SessionMetricsStats setSessionDurationSec(int sessionDurationSec) {
+        logd("setSessionDuration(" + sessionDurationSec + ")");
+        mSessionDurationSec = sessionDurationSec;
+        return this;
+    }
+
+    /** Increase the count of successful outgoing datagram transmission. */
+    public SessionMetricsStats addCountOfSuccessfulOutgoingDatagram() {
+        mCountOfSuccessfulOutgoingDatagram++;
+        logd("addCountOfSuccessfulOutgoingDatagram: current count="
+                + mCountOfSuccessfulOutgoingDatagram);
+        return this;
+    }
+
+    /** Increase the count of failed outgoing datagram transmission. */
+    public SessionMetricsStats addCountOfFailedOutgoingDatagram() {
+        mCountOfFailedOutgoingDatagram++;
+        logd("addCountOfFailedOutgoingDatagram: current count=" + mCountOfFailedOutgoingDatagram);
+        return this;
+    }
+
+    /** Increase the count of successful incoming datagram transmission. */
+    public SessionMetricsStats addCountOfSuccessfulIncomingDatagram() {
+        mCountOfSuccessfulIncomingDatagram++;
+        logd("addCountOfSuccessfulIncomingDatagram: current count="
+                + mCountOfSuccessfulIncomingDatagram);
+        return this;
+    }
+
+    /** Increase the count of failed incoming datagram transmission. */
+    public SessionMetricsStats addCountOfFailedIncomingDatagram() {
+        mCountOfIncomingDatagramFailed++;
+        logd("addCountOfFailedIncomingDatagram: current count=" + mCountOfIncomingDatagramFailed);
+        return this;
+    }
+
+    /** Report the session metrics atoms to PersistAtomsStorage in telephony. */
     public void reportSessionMetrics() {
         SatelliteStats.SatelliteSessionParams sessionParams =
                 new SatelliteStats.SatelliteSessionParams.Builder()
                         .setSatelliteServiceInitializationResult(mInitializationResult)
                         .setSatelliteTechnology(mRadioTechnology)
+                        .setTerminationResult(mTerminationResult)
+                        .setInitializationProcessingTime(mInitializationProcessingTimeMillis)
+                        .setTerminationProcessingTime(mTerminationProcessingTimeMillis)
+                        .setSessionDuration(mSessionDurationSec)
+                        .setCountOfOutgoingDatagramSuccess(mCountOfSuccessfulOutgoingDatagram)
+                        .setCountOfOutgoingDatagramFailed(mCountOfFailedOutgoingDatagram)
+                        .setCountOfIncomingDatagramSuccess(mCountOfSuccessfulIncomingDatagram)
+                        .setCountOfIncomingDatagramFailed(mCountOfIncomingDatagramFailed)
                         .build();
-        logd(sessionParams.toString());
+        logd("reportSessionMetrics: " + sessionParams.toString());
         SatelliteStats.getInstance().onSatelliteSessionMetrics(sessionParams);
         initializeSessionMetricsParam();
     }
 
+    /** Returns the processing time for satellite session initialization. */
+    public long getSessionInitializationProcessingTimeMillis() {
+        return mInitializationProcessingTimeMillis;
+    }
+
+    /** Returns the processing time for satellite session termination. */
+    public long getSessionTerminationProcessingTimeMillis() {
+        return mTerminationProcessingTimeMillis;
+    }
+
     private void initializeSessionMetricsParam() {
         mInitializationResult = SatelliteManager.SATELLITE_RESULT_SUCCESS;
         mRadioTechnology = SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
+        mTerminationResult = SatelliteManager.SATELLITE_RESULT_SUCCESS;
+        mInitializationProcessingTimeMillis = 0;
+        mTerminationProcessingTimeMillis = 0;
+        mSessionDurationSec = 0;
+        mCountOfSuccessfulOutgoingDatagram = 0;
+        mCountOfFailedOutgoingDatagram = 0;
+        mCountOfSuccessfulIncomingDatagram = 0;
+        mCountOfIncomingDatagramFailed = 0;
     }
 
     private static void logd(@NonNull String log) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
index 1f9ace9..8420acf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -1518,6 +1518,53 @@
     }
 
     @Test
+    public void testSetPreferredDataCallback_voiceCall() throws Exception {
+        doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+        initialize();
+        setAllPhonesInactive();
+
+        // Phone 0 has sub 1, phone 1 has sub 2.
+        // Sub 1 is default data sub.
+        // Both are active subscriptions are active sub, as they are in both active slots.
+        setSlotIndexToSubId(0, 1);
+        setSlotIndexToSubId(1, 2);
+        setDefaultDataSubId(1);
+        assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId());
+
+        doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService
+                .getSubscriptionInfoInternal(2)).setOpportunistic(1).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2);
+
+        // First temporarily switched to the opportunistic sub 2
+        mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1);
+        processAllMessages();
+        mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2);
+        processAllMessages();
+        verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS);
+
+        // Voice call led back to default sub 1
+        doReturn(mImsPhone).when(mPhone).getImsPhone();
+        doReturn(true).when(mPhone).isUserDataEnabled();
+        doReturn(true).when(mDataSettingsManager).isDataEnabled();
+        mockImsRegTech(0, REGISTRATION_TECH_LTE);
+        notifyPhoneAsInCall(mPhone);
+
+        assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId());
+        assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId());
+
+        // CBRS set preferred data back to default during the phone call
+        clearInvocations(mSetOpptDataCallback1);
+        mPhoneSwitcherUT.trySetOpportunisticDataSubscription(SubscriptionManager
+                .DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1);
+        processAllMessages();
+
+        verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS);
+        assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId());
+        assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                mPhoneSwitcherUT.getAutoSelectedDataSubId());
+    }
+
+    @Test
     @SmallTest
     public void testMultiSimConfigChange() throws Exception {
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
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 4edaa83..6260761 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -260,6 +260,46 @@
         verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any());
     }
 
+    @Test
+    @SmallTest
+    public void startEmergencyCall_radioOff_turnOnRadioHangupCallTurnOffRadio() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                true /* isSuplDdsSwitchRequiredForEmergencyCall */);
+        // Create test Phones and set radio off
+        Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */,
+                false /* isRadioOn */);
+        setConfigForDdsSwitch(testPhone, null,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "150");
+        ServiceState ss = mock(ServiceState.class);
+        doReturn(ss).when(mSST).getServiceState();
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .build();
+        doReturn(nri).when(ss).getNetworkRegistrationInfo(anyInt(), anyInt());
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(testPhone,
+                mTestConnection1, false);
+
+        // startEmergencyCall should trigger radio on
+        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));
+
+        // Hangup the call
+        emergencyStateTracker.endCall(mTestConnection1);
+
+        // onTimeout and isOkToCall should return true even in case radion is off
+        assertTrue(callback.getValue()
+                .isOkToCall(testPhone, ServiceState.STATE_POWER_OFF, false));
+        assertTrue(callback.getValue()
+                .onTimeout(testPhone, ServiceState.STATE_POWER_OFF, false));
+
+        callback.getValue().onComplete(null, true);
+
+        assertFalse(future.isDone());
+    }
+
     /**
      * Test that if startEmergencyCall fails to turn on radio, then it's future completes with
      * DisconnectCause.POWER_OFF.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
index d63dc3c..2e64c46 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -19,7 +19,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -308,4 +310,49 @@
         assertTrue(stats.oosAtEnd);
         assertFalse(stats.ongoing);
     }
+
+    @Test
+    public void testIsNtn() {
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+
+        mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+        mDataCallSessionStats.onSetupDataCallResponse(
+                mDefaultImsResponse,
+                TelephonyManager.NETWORK_TYPE_LTE,
+                ApnSetting.TYPE_IMS,
+                ApnSetting.PROTOCOL_IP,
+                DataFailCause.NONE);
+
+        mDataCallSessionStats.setTimeMillis(60000L);
+        mDataCallSessionStats.conclude();
+
+        ArgumentCaptor<DataCallSession> callCaptor =
+                ArgumentCaptor.forClass(DataCallSession.class);
+        verify(mPersistAtomsStorage).addDataCallSession(callCaptor.capture());
+        DataCallSession stats = callCaptor.getValue();
+
+        assertTrue(stats.isNtn);
+
+        reset(mPersistAtomsStorage);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any()))
+                .thenReturn(false);
+
+        mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+        mDataCallSessionStats.onSetupDataCallResponse(
+                mDefaultImsResponse,
+                TelephonyManager.NETWORK_TYPE_LTE,
+                ApnSetting.TYPE_IMS,
+                ApnSetting.PROTOCOL_IP,
+                DataFailCause.NONE);
+
+        mDataCallSessionStats.setTimeMillis(60000L);
+        mDataCallSessionStats.conclude();
+
+
+        verify(mPersistAtomsStorage).addDataCallSession(callCaptor.capture());
+        stats = callCaptor.getValue();
+
+        assertFalse(stats.isNtn);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
index 75ef7ec..b9f58c4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
@@ -1123,6 +1123,15 @@
         mSatelliteSession1.satelliteTechnology =
                 SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_PROPRIETARY;
         mSatelliteSession1.count = 1;
+        mSatelliteSession1.satelliteServiceTerminationResult =
+                SatelliteProtoEnums.SATELLITE_ERROR_NONE;
+        mSatelliteSession1.initializationProcessingTimeMillis = 100;
+        mSatelliteSession1.terminationProcessingTimeMillis = 200;
+        mSatelliteSession1.sessionDurationSeconds = 3;
+        mSatelliteSession1.countOfOutgoingDatagramSuccess = 1;
+        mSatelliteSession1.countOfOutgoingDatagramFailed = 0;
+        mSatelliteSession1.countOfIncomingDatagramSuccess = 1;
+        mSatelliteSession1.countOfIncomingDatagramFailed = 0;
 
         mSatelliteSession2 = new SatelliteSession();
         mSatelliteSession2.satelliteServiceInitializationResult =
@@ -1130,6 +1139,15 @@
         mSatelliteSession2.satelliteTechnology =
                 SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_NB_IOT_NTN;
         mSatelliteSession2.count = 1;
+        mSatelliteSession1.satelliteServiceTerminationResult =
+                SatelliteProtoEnums.SATELLITE_ERROR_NONE;
+        mSatelliteSession1.initializationProcessingTimeMillis = 300;
+        mSatelliteSession1.terminationProcessingTimeMillis = 100;
+        mSatelliteSession1.sessionDurationSeconds = 10;
+        mSatelliteSession1.countOfOutgoingDatagramSuccess = 0;
+        mSatelliteSession1.countOfOutgoingDatagramFailed = 2;
+        mSatelliteSession1.countOfIncomingDatagramSuccess = 0;
+        mSatelliteSession1.countOfIncomingDatagramFailed = 1;
 
         mSatelliteSessions =
                 new SatelliteSession[] {
@@ -4944,7 +4962,22 @@
         for (SatelliteSession stats : tested) {
             if (stats.satelliteServiceInitializationResult
                     == expectedStats.satelliteServiceInitializationResult
-                    && stats.satelliteTechnology == expectedStats.satelliteTechnology) {
+                    && stats.satelliteTechnology == expectedStats.satelliteTechnology
+                    && stats.satelliteServiceTerminationResult
+                    == expectedStats.satelliteServiceTerminationResult
+                    && stats.initializationProcessingTimeMillis
+                    == expectedStats.initializationProcessingTimeMillis
+                    && stats.terminationProcessingTimeMillis
+                    == expectedStats.terminationProcessingTimeMillis
+                    && stats.sessionDurationSeconds == expectedStats.sessionDurationSeconds
+                    && stats.countOfOutgoingDatagramSuccess
+                    == expectedStats.countOfOutgoingDatagramSuccess
+                    && stats.countOfOutgoingDatagramFailed
+                    == expectedStats.countOfOutgoingDatagramFailed
+                    && stats.countOfIncomingDatagramSuccess
+                    == expectedStats.countOfIncomingDatagramSuccess
+                    && stats.countOfIncomingDatagramFailed
+                    == expectedStats.countOfIncomingDatagramFailed) {
                 actualCount = stats.count;
             }
         }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
index 959b643..0081dc6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
@@ -134,6 +134,14 @@
                         .setSatelliteServiceInitializationResult(
                                 SatelliteProtoEnums.SATELLITE_ERROR_NONE)
                         .setSatelliteTechnology(SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_PROPRIETARY)
+                        .setTerminationResult(SatelliteProtoEnums.SATELLITE_ERROR_NONE)
+                        .setInitializationProcessingTime(100)
+                        .setTerminationProcessingTime(200)
+                        .setSessionDuration(3)
+                        .setCountOfOutgoingDatagramSuccess(1)
+                        .setCountOfOutgoingDatagramFailed(0)
+                        .setCountOfIncomingDatagramSuccess(1)
+                        .setCountOfIncomingDatagramFailed(0)
                         .build();
 
         mSatelliteStats.onSatelliteSessionMetrics(param);
@@ -144,7 +152,18 @@
         SatelliteSession stats = captor.getValue();
         assertEquals(param.getSatelliteServiceInitializationResult(),
                 stats.satelliteServiceInitializationResult);
-        assertEquals(param.getSatelliteTechnology(), stats.satelliteTechnology);
+        assertEquals(param.getTerminationResult(), stats.satelliteServiceTerminationResult);
+        assertEquals(param.getInitializationProcessingTime(),
+                stats.initializationProcessingTimeMillis);
+        assertEquals(param.getTerminationProcessingTime(), stats.terminationProcessingTimeMillis);
+        assertEquals(param.getSessionDuration(), stats.sessionDurationSeconds);
+        assertEquals(param.getCountOfOutgoingDatagramSuccess(),
+                stats.countOfOutgoingDatagramSuccess);
+        assertEquals(param.getCountOfOutgoingDatagramFailed(), stats.countOfOutgoingDatagramFailed);
+        assertEquals(param.getCountOfIncomingDatagramSuccess(),
+                stats.countOfIncomingDatagramSuccess);
+        assertEquals(param.getCountOfIncomingDatagramFailed(), stats.countOfIncomingDatagramFailed);
+
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
index 16dab44..27878d1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
@@ -30,15 +30,20 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.NetworkRegistrationInfo;
@@ -58,6 +63,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
@@ -76,6 +82,9 @@
 
     private TestableServiceStateStats mServiceStateStats;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static class TestableServiceStateStats extends ServiceStateStats {
         private long mTimeMillis = START_TIME_MILLIS;
 
@@ -1324,6 +1333,34 @@
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
+    @Test
+    public void testIsNtn() {
+        // Using default service state for LTE
+        mServiceStateStats.onServiceStateChanged(mServiceState);
+        mServiceStateStats.incTimeMillis(100L);
+        mServiceStateStats.conclude();
+
+        ArgumentCaptor<CellularServiceState> captor =
+                ArgumentCaptor.forClass(CellularServiceState.class);
+        verify(mPersistAtomsStorage)
+                .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+        CellularServiceState state = captor.getValue();
+        assertFalse(state.isNtn);
+
+        reset(mPersistAtomsStorage);
+        reset(mServiceState);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+        mServiceStateStats.onServiceStateChanged(mServiceState);
+        mServiceStateStats.incTimeMillis(100L);
+        mServiceStateStats.conclude();
+
+        verify(mPersistAtomsStorage)
+                .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+        state = captor.getValue();
+        assertTrue(state.isNtn);
+    }
+
     private void mockWwanPsRat(@NetworkType int rat) {
         mockWwanRat(
                 NetworkRegistrationInfo.DOMAIN_PS,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
index 58cc516..edc481a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
@@ -34,15 +34,19 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.os.Looper;
@@ -2753,6 +2757,36 @@
         assertProtoEquals(expectedRatUsage, ratUsage.get()[0]);
     }
 
+    @Test
+    public void testIsNtn() {
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+
+        mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+        mVoiceCallSessionStats0.setTimeMillis(2200L);
+        mVoiceCallSessionStats0.onImsCallTerminated(mImsConnection0,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, 0));
+
+        ArgumentCaptor<VoiceCallSession> callCaptor =
+                ArgumentCaptor.forClass(VoiceCallSession.class);
+        verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+        VoiceCallSession session = callCaptor.getValue();
+        assertTrue(session.isNtn);
+
+        reset(mPersistAtomsStorage);
+        reset(mServiceState);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any()))
+                .thenReturn(false);
+        mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+        mVoiceCallSessionStats0.setTimeMillis(2200L);
+        mVoiceCallSessionStats0.onImsCallTerminated(mImsConnection0,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, 0));
+
+        verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+        session = callCaptor.getValue();
+        assertFalse(session.isNtn);
+    }
+
     private AtomicReference<VoiceCallRatUsage[]> setupRatUsageCapture() {
         final AtomicReference<VoiceCallRatUsage[]> ratUsage = new AtomicReference<>(null);
         doAnswer(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
index e6689dd..78322ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
@@ -16,7 +16,10 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING;
 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
@@ -77,10 +80,10 @@
                 mContext, Looper.myLooper(), mMockPointingAppController);
 
         // Move both send and receive to IDLE state
-        mDatagramControllerUT.updateSendStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                0, SATELLITE_RESULT_SUCCESS);
-        mDatagramControllerUT.updateReceiveStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                0, SATELLITE_RESULT_SUCCESS);
+        mDatagramControllerUT.updateSendStatus(SUB_ID, DATAGRAM_TYPE_UNKNOWN,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, SATELLITE_RESULT_SUCCESS);
+        mDatagramControllerUT.updateReceiveStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
+                SATELLITE_RESULT_SUCCESS);
         pushDemoModeSosDatagram();
     }
 
@@ -92,9 +95,12 @@
 
     @Test
     public void testUpdateSendStatus() throws Exception {
-        testUpdateSendStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
-        testUpdateSendStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
-        testUpdateSendStatus(false, SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
+        testUpdateSendStatus(true, DATAGRAM_TYPE_SOS_MESSAGE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
+        testUpdateSendStatus(true, DATAGRAM_TYPE_LOCATION_SHARING,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        testUpdateSendStatus(false, DATAGRAM_TYPE_KEEP_ALIVE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
     }
 
     @Test
@@ -110,18 +116,19 @@
         testSetDeviceAlignedWithSatellite(false);
     }
 
-    private void testUpdateSendStatus(boolean isDemoMode, int sendState) {
+    private void testUpdateSendStatus(boolean isDemoMode, int datagramType, int sendState) {
         mDatagramControllerUT.setDemoMode(isDemoMode);
         clearAllInvocations();
 
         int sendPendingCount = 1;
         int errorCode = SATELLITE_RESULT_SUCCESS;
-        mDatagramControllerUT.updateSendStatus(SUB_ID, sendState, sendPendingCount, errorCode);
+        mDatagramControllerUT.updateSendStatus(SUB_ID, datagramType, sendState, sendPendingCount,
+                errorCode);
 
         verify(mMockSatelliteSessionController)
                 .onDatagramTransferStateChanged(eq(sendState), anyInt());
         verify(mMockPointingAppController).updateSendDatagramTransferState(
-                eq(SUB_ID), eq(sendState), eq(sendPendingCount), eq(errorCode));
+                eq(SUB_ID), eq(datagramType), eq(sendState), eq(sendPendingCount), eq(errorCode));
 
         if (isDemoMode) {
             if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
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 cfb8a8d..3708a47 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -61,6 +61,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
+import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -84,6 +85,7 @@
     private static final int SUB_ID = 0;
     private static final int DATAGRAM_TYPE1 = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE;
     private static final int DATAGRAM_TYPE2 = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING;
+    private static final int DATAGRAM_TYPE3 = SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE;
     private static final String TEST_MESSAGE = "This is a test datagram message";
     private static final long TEST_EXPIRE_TIMER_SATELLITE_ALIGN = TimeUnit.SECONDS.toMillis(1);
     private static final int TEST_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMEOUT_MILLIS =
@@ -99,6 +101,7 @@
     @Mock private SatelliteModemInterface mMockSatelliteModemInterface;
     @Mock private ControllerMetricsStats mMockControllerMetricsStats;
     @Mock private SatelliteSessionController mMockSatelliteSessionController;
+    @Mock private SessionMetricsStats mMockSessionMetricsStats;
 
     /** Variables required to send datagram in the unit tests. */
     LinkedBlockingQueue<Integer> mResultListener;
@@ -137,6 +140,8 @@
                 mMockControllerMetricsStats);
         replaceInstance(SatelliteSessionController.class, "sInstance", null,
                 mMockSatelliteSessionController);
+        replaceInstance(SessionMetricsStats.class, "sInstance", null,
+                mMockSessionMetricsStats);
 
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         mDatagramDispatcherUT = new TestDatagramDispatcher(mContext, Looper.myLooper(),
@@ -180,7 +185,7 @@
                 true, mResultListener::offer);
         processAllMessages();
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
-        mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID),
+        mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                 eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(1),
                 eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
@@ -193,18 +198,19 @@
 
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulOutgoingDatagram();
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
         assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
@@ -231,16 +237,19 @@
         verifyZeroInteractions(mMockSatelliteModemInterface);
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1),
                         eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         assertEquals(1, mResultListener.size());
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
         assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedOutgoingDatagram();
 
         mResultListener.clear();
         mDatagramDispatcherUT.onSatelliteModemStateChanged(
@@ -269,6 +278,7 @@
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
         assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedOutgoingDatagram();
     }
 
     @Test
@@ -303,22 +313,22 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
         assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
-
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulOutgoingDatagram();
         clearInvocations(mMockSatelliteModemInterface);
         clearInvocations(mMockDatagramController);
         mResultListener.clear();
@@ -333,15 +343,15 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1),
                         eq(SATELLITE_RESULT_MODEM_TIMEOUT));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
@@ -349,6 +359,7 @@
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
         verify(mMockSatelliteModemInterface).abortSendingSatelliteDatagrams(any(Message.class));
         assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_MODEM_TIMEOUT);
+        verify(mMockSessionMetricsStats, never()).addCountOfFailedOutgoingDatagram();
     }
 
     @Test
@@ -373,21 +384,22 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0),
                         eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
 
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedOutgoingDatagram();
     }
 
     @Test
@@ -411,18 +423,19 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulOutgoingDatagram();
         mDatagramDispatcherUT.setDemoMode(false);
         mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
     }
@@ -447,16 +460,16 @@
                 true, mResultListener::offer);
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
         processAllFutureMessages();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED),
                         anyInt(), eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
         assertThat(mResultListener.peek()).isEqualTo(
@@ -464,6 +477,7 @@
         verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any());
         verify(mMockDatagramController, never()).pushDemoModeDatagram(
                 anyInt(), any(SatelliteDatagram.class));
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedOutgoingDatagram();
         mDatagramDispatcherUT.setDemoMode(false);
         mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
         mDatagramDispatcherUT.setDuration(previousTimer);
@@ -491,21 +505,22 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
 
         assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
                         eq(SATELLITE_RESULT_SUCCESS));
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulOutgoingDatagram();
 
         mDatagramDispatcherUT.setDemoMode(false);
         mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
@@ -543,11 +558,11 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED),
                         eq(1), eq(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
                         eq(0), eq(SATELLITE_RESULT_SUCCESS));
     }
@@ -560,7 +575,7 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), anyInt(),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
                         eq(0), eq(SATELLITE_RESULT_SUCCESS));
     }
@@ -602,6 +617,7 @@
         verify(mMockDatagramController).pushDemoModeDatagram(
                 anyInt(), any(SatelliteDatagram.class));
         verify(mMockDatagramController).pollPendingSatelliteDatagrams(anyInt(), any());
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulOutgoingDatagram();
 
         // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is false
         reset(mMockSatelliteModemInterface);
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 0a07f03..7eae18b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -58,6 +58,7 @@
 import com.android.internal.telephony.IVoidConsumer;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
+import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -90,6 +91,7 @@
     @Mock private SatelliteModemInterface mMockSatelliteModemInterface;
     @Mock private ControllerMetricsStats mMockControllerMetricsStats;
     @Mock private SatelliteSessionController mMockSatelliteSessionController;
+    @Mock private SessionMetricsStats mMockSessionMetricsStats;
 
     /** Variables required to receive datagrams in the unit tests. */
     LinkedBlockingQueue<Integer> mResultListener;
@@ -120,6 +122,8 @@
                 mMockControllerMetricsStats);
         replaceInstance(SatelliteSessionController.class, "sInstance", null,
                 mMockSatelliteSessionController);
+        replaceInstance(SessionMetricsStats.class, "sInstance", null,
+                mMockSessionMetricsStats);
 
         mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(),
                 mMockDatagramController);
@@ -194,6 +198,7 @@
         assertFalse(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted());
 
         clearInvocations(mMockSatelliteModemInterface);
+        clearInvocations(mMockSessionMetricsStats);
         mResultListener.clear();
         doReturn(true).when(mMockDatagramController).needsWaitingForSatelliteConnected();
         mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
@@ -215,6 +220,7 @@
         assertEquals(1, mResultListener.size());
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedIncomingDatagram();
         assertFalse(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted());
 
         mResultListener.clear();
@@ -255,6 +261,8 @@
 
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedIncomingDatagram();
     }
 
     @Test
@@ -273,6 +281,8 @@
                 .updateReceiveStatus(eq(SUB_ID),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
                         eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+
+        verify(mMockSessionMetricsStats, never()).addCountOfFailedIncomingDatagram();
     }
 
     @Test
@@ -295,6 +305,7 @@
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
                         eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         assertTrue(testSatelliteDatagramCallback.waitForOnSatelliteDatagramReceived());
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulIncomingDatagram();
 
         assertTrue(testSatelliteDatagramCallback.sendInternalAck());
         try {
@@ -316,6 +327,7 @@
                 .updateReceiveStatus(eq(SUB_ID),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS),
                         eq(10), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+        verify(mMockSessionMetricsStats, times(1)).addCountOfSuccessfulIncomingDatagram();
     }
 
     @Test
@@ -376,6 +388,7 @@
                         eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         assertThat(mResultListener.peek())
                 .isEqualTo(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+        verify(mMockSessionMetricsStats, times(1)).addCountOfFailedIncomingDatagram();
 
         mTestDemoModeDatagramReceiver.setDemoMode(false);
         mTestDemoModeDatagramReceiver.setDeviceAlignedWithSatellite(false);
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 3917a32..0fe48c8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
@@ -150,6 +150,7 @@
     }
     private class TestSatelliteTransmissionUpdateCallback
                                 extends ISatelliteTransmissionUpdateCallback.Stub {
+        int mDatagramType;
         int mState;
         int mSendPendingCount;
         int mReceivePendingCount;
@@ -163,8 +164,9 @@
         }
 
         @Override
-        public void onSendDatagramStateChanged(int state, int sendPendingCount,
+        public void onSendDatagramStateChanged(int datagramType, int state, int sendPendingCount,
                                     int errorCode) {
+            mDatagramType = datagramType;
             mState = state;
             mSendPendingCount = sendPendingCount;
             mErrorCode = errorCode;
@@ -191,6 +193,10 @@
             }
         }
 
+        public int getDatagramType() {
+            return mDatagramType;
+        }
+
         public int getState() {
             return mState;
         }
@@ -208,7 +214,7 @@
         }
     }
 
-    private boolean waitForReceiveDatagramStateChangedRessult(
+    private boolean waitForReceiveDatagramStateChangedResult(
             int expectedNumberOfEvents) {
         for (int i = 0; i < expectedNumberOfEvents; i++) {
             try {
@@ -218,7 +224,7 @@
                     return false;
                 }
             } catch (Exception ex) {
-                loge("waitForReceiveDatagramStateChangedRessult: Got exception=" + ex);
+                loge("waitForReceiveDatagramStateChangedResult: Got exception=" + ex);
                 return false;
             }
         }
@@ -347,9 +353,12 @@
         mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID,
                 mSatelliteTransmissionUpdateCallback);
         mPointingAppController.updateSendDatagramTransferState(SUB_ID,
+                SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, 1,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
         assertTrue(waitForSendDatagramStateChangedRessult(1));
+        assertEquals(SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE,
+                mSatelliteTransmissionUpdateCallback.getDatagramType());
         assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
                 mSatelliteTransmissionUpdateCallback.getState());
         assertEquals(1, mSatelliteTransmissionUpdateCallback.getSendPendingCount());
@@ -368,7 +377,7 @@
         mPointingAppController.updateReceiveDatagramTransferState(SUB_ID,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, 2,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        assertTrue(waitForReceiveDatagramStateChangedRessult(1));
+        assertTrue(waitForReceiveDatagramStateChangedResult(1));
         assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS,
                 mSatelliteTransmissionUpdateCallback.getState());
         assertEquals(2, mSatelliteTransmissionUpdateCallback.getReceivePendingCount());
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 9d05525..c38b6a9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
 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.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
@@ -57,6 +58,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
+import static com.android.internal.telephony.satellite.SatelliteController.DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_FALSE;
 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_TRUE;
 
@@ -70,6 +72,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.anyVararg;
 import static org.mockito.ArgumentMatchers.eq;
@@ -514,13 +517,21 @@
         doReturn(mMockSessionMetricsStats)
                 .when(mMockSessionMetricsStats).setInitializationResult(anyInt());
         doReturn(mMockSessionMetricsStats)
-                .when(mMockSessionMetricsStats).setRadioTechnology(anyInt());
+                .when(mMockSessionMetricsStats).setSatelliteTechnology(anyInt());
+        doReturn(mMockSessionMetricsStats)
+                .when(mMockSessionMetricsStats).setTerminationResult(anyInt());
+        doReturn(mMockSessionMetricsStats)
+                .when(mMockSessionMetricsStats).setInitializationProcessingTime(anyLong());
+        doReturn(mMockSessionMetricsStats)
+                .when(mMockSessionMetricsStats).setTerminationProcessingTime(anyLong());
+        doReturn(mMockSessionMetricsStats)
+                .when(mMockSessionMetricsStats).setSessionDurationSec(anyInt());
         doNothing().when(mMockSessionMetricsStats).reportSessionMetrics();
 
         doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats)
                 .setResultCode(anyInt());
         doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats)
-                .setIsProvisionRequest(eq(false));
+                .setIsProvisionRequest(anyBoolean());
         doNothing().when(mMockProvisionMetricsStats).reportProvisionMetrics();
         doNothing().when(mMockControllerMetricsStats).reportDeprovisionCount(anyInt());
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
@@ -812,9 +823,6 @@
         verify(mMockDatagramController, times(4)).setDemoMode(eq(false));
         verify(mMockControllerMetricsStats, times(2)).onSatelliteEnabled();
         verify(mMockControllerMetricsStats, times(2)).reportServiceEnablementSuccessCount();
-        verify(mMockSessionMetricsStats, times(7)).setInitializationResult(anyInt());
-        verify(mMockSessionMetricsStats, times(7)).setRadioTechnology(anyInt());
-        verify(mMockSessionMetricsStats, times(7)).reportSessionMetrics();
 
         // Successfully enable satellite when it is already enabled.
         mIIntegerConsumerResults.clear();
@@ -902,6 +910,14 @@
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0));
 
+        verify(mMockSessionMetricsStats, times(15)).setInitializationResult(anyInt());
+        verify(mMockSessionMetricsStats, times(15)).setSatelliteTechnology(anyInt());
+        verify(mMockSessionMetricsStats, times(3)).setInitializationProcessingTime(anyLong());
+        verify(mMockSessionMetricsStats, times(2)).setTerminationResult(anyInt());
+        verify(mMockSessionMetricsStats, times(2)).setTerminationProcessingTime(anyLong());
+        verify(mMockSessionMetricsStats, times(2)).setSessionDurationSec(anyInt());
+        verify(mMockSessionMetricsStats, times(15)).reportSessionMetrics();
+
         /**
          * Make areAllRadiosDisabled return false and move mWaitingForRadioDisabled to true, which
          * will lead to no response for requestSatelliteEnabled.
@@ -1656,7 +1672,7 @@
     }
 
     @Test
-    public void testSupportedSatelliteServices() {
+    public void testSupportedSatelliteServices() throws Exception {
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
         List<String> satellitePlmnList = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
                 SUB_ID);
@@ -1670,6 +1686,7 @@
                 R.array.config_satellite_providers, satelliteProviderStrArray);
         int[] expectedSupportedServices2 = {2};
         int[] expectedSupportedServices3 = {1, 3};
+        int[] defaultSupportedServices = {5, 6};
         PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle();
         carrierSupportedSatelliteServicesPerProvider.putIntArray(
                 "00102", expectedSupportedServices2);
@@ -1679,6 +1696,9 @@
         mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
                         .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 carrierSupportedSatelliteServicesPerProvider);
+        mCarrierConfigBundle.putIntArray(
+                CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
+                defaultSupportedServices);
         TestSatelliteController testSatelliteController =
                 new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags);
 
@@ -1688,6 +1708,9 @@
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101");
         assertTrue(supportedSatelliteServices.isEmpty());
 
+        // Add entitlement provided PLMNs.
+        setEntitlementPlmnList(testSatelliteController, SUB_ID,
+                Arrays.asList("00102", "00104", "00105"));
         // Carrier config changed with carrierEnabledSatelliteFlag disabled
         for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
                 : mCarrierConfigChangedListenerList) {
@@ -1703,6 +1726,12 @@
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103");
         assertTrue(supportedSatelliteServices.isEmpty());
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(supportedSatelliteServices.isEmpty());
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(supportedSatelliteServices.isEmpty());
 
         // Trigger carrier config changed with carrierEnabledSatelliteFlag enabled
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
@@ -1721,6 +1750,7 @@
                 expectedSupportedSatellitePlmns, satellitePlmnList.stream().toArray()));
         supportedSatelliteServices =
                 mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00102");
+        // "00101" should return carrier config assigned value, though it is in allowed list.
         assertTrue(Arrays.equals(expectedSupportedServices2,
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
@@ -1731,6 +1761,19 @@
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
                         .toArray()));
+        // "00104", and "00105" should return default supported service.
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
 
         // Subscriptions changed
         int[] newActiveSubIds = {SUB_ID1};
@@ -1745,13 +1788,32 @@
 
         satellitePlmnList = testSatelliteController.getSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(satellitePlmnList.isEmpty());
+        // "00102" and "00103" should return default supported service for SUB_ID.
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102");
-        assertTrue(supportedSatelliteServices.isEmpty());
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103");
-        assertTrue(supportedSatelliteServices.isEmpty());
-
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        // "00104", and "00105" should return default supported service for SUB_ID.
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
 
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00102");
@@ -1767,6 +1829,19 @@
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
                         .toArray()));
+        /* "00104", and "00105" should return default supported service. */
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
     }
 
     @Test
@@ -2904,6 +2979,17 @@
                 mSatelliteControllerUT, entitlementPlmnListPerCarrier);
     }
 
+    private void setEntitlementPlmnList(SatelliteController targetClass, int subId,
+            List<String> plmnList) throws Exception {
+        SparseArray<List<String>> entitlementPlmnListPerCarrier = new SparseArray<>();
+        if (!plmnList.isEmpty()) {
+            entitlementPlmnListPerCarrier.clear();
+            entitlementPlmnListPerCarrier.put(subId, plmnList);
+        }
+        replaceInstance(SatelliteController.class, "mEntitlementPlmnListPerCarrier",
+                targetClass, entitlementPlmnListPerCarrier);
+    }
+
     private void setConfigDataPlmnList(List<String> plmnList) {
         doReturn(plmnList).when(mMockConfig).getAllSatellitePlmnsForCarrier(anyInt());
         doReturn(mMockConfig).when(mMockConfigParser).getConfig();
@@ -3484,6 +3570,105 @@
         assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
     }
 
+    @Test
+    public void testIsSatelliteEmergencyMessagingSupportedViaCarrier() {
+        // Carrier-enabled flag is off
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Carrier-enabled flag is on and satellite attach is not supported
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Trigger carrier config changed to enable satellite attach
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Trigger carrier config changed to enable satellite attach & emergency messaging
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+        assertTrue(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+    }
+
+    @Test
+    public void testGetCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+        // Carrier-enabled flag is off
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+        assertEquals(DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Carrier-enabled flag is on
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        assertEquals(DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Trigger carrier config changed to enable satellite attach
+        int timeoutMillisForCarrier1 = 1000;
+        PersistableBundle carrierConfigBundle1 = new PersistableBundle();
+        carrierConfigBundle1.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        carrierConfigBundle1.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        carrierConfigBundle1.putInt(
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
+                timeoutMillisForCarrier1);
+        doReturn(carrierConfigBundle1)
+                .when(mCarrierConfigManager).getConfigForSubId(eq(SUB_ID), anyVararg());
+
+        int timeoutMillisForCarrier2 = 2000;
+        PersistableBundle carrierConfigBundle2 = new PersistableBundle();
+        carrierConfigBundle2.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        carrierConfigBundle2.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        carrierConfigBundle2.putInt(
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
+                timeoutMillisForCarrier2);
+        doReturn(carrierConfigBundle2)
+                .when(mCarrierConfigManager).getConfigForSubId(eq(SUB_ID1), anyVararg());
+
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+
+        // Both phones are not in satellite mode for carrier roaming, and thus the max timeout
+        // duration - timeoutMillisForCarrier2 - is used
+        assertEquals(timeoutMillisForCarrier2,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Phone 1 is in satellite mode for carrier roaming
+        when(mServiceState.isUsingNonTerrestrialNetwork()).thenReturn(true);
+        assertEquals(timeoutMillisForCarrier1,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Both phones are in satellite mode for carrier roaming. The timeout duration of the first
+        // phone will be selected
+        when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(true);
+        assertEquals(timeoutMillisForCarrier1,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+    }
+
     private void resetSatelliteControllerUTEnabledState() {
         logd("resetSatelliteControllerUTEnabledState");
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index d12828a..fc04688 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -38,11 +38,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.OutcomeReceiver;
 import android.os.RemoteException;
 import android.telecom.Connection;
+import android.telecom.TelecomManager;
 import android.telephony.BinderCacheManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -86,7 +88,7 @@
 @TestableLooper.RunWithLooper
 public class SatelliteSOSMessageRecommenderTest extends TelephonyTest {
     private static final String TAG = "SatelliteSOSMessageRecommenderTest";
-    private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
+    private static final int TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
     private static final int PHONE_ID = 0;
     private static final int PHONE_ID2 = 1;
     private static final String CALL_ID = "CALL_ID";
@@ -96,6 +98,7 @@
             "android.com.google.default.SmsMmsApp";
     private static final String DEFAULT_HANDOVER_INTENT_ACTION =
             "android.com.vendor.action.EMERGENCY_MESSAGING";
+    private static final String DEFAULT_T911_HANDOVER_INTENT_ACTION = Intent.ACTION_SENDTO;
     private TestSatelliteController mTestSatelliteController;
     private TestImsManager mTestImsManager;
     @Mock
@@ -105,6 +108,7 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     private TestConnection mTestConnection;
+    private Uri mTestConnectionAddress = Uri.parse("tel:1234");
     private TestSOSMessageRecommender mTestSOSMessageRecommender;
     private ServiceState mServiceState2;
 
@@ -118,12 +122,16 @@
                 .thenReturn("");
         when(mResources.getString(R.string.config_satellite_emergency_handover_intent_action))
                 .thenReturn(DEFAULT_HANDOVER_INTENT_ACTION);
+        when(mResources.getInteger(
+                R.integer.config_emergency_call_wait_for_connection_timeout_millis))
+                .thenReturn(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         mTestSatelliteController = new TestSatelliteController(mContext,
                 Looper.myLooper(), mFeatureFlags);
         mTestImsManager = new TestImsManager(
                 mContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null);
         mTestConnection = new TestConnection(CALL_ID);
+        mTestConnection.setAddress(mTestConnectionAddress, TelecomManager.PRESENTATION_ALLOWED);
         mPhones = new Phone[] {mPhone, mPhone2};
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
         mServiceState2 = Mockito.mock(ServiceState.class);
@@ -132,8 +140,7 @@
         when(mPhone2.getServiceState()).thenReturn(mServiceState2);
         when(mPhone2.getPhoneId()).thenReturn(PHONE_ID2);
         mTestSOSMessageRecommender = new TestSOSMessageRecommender(mContext, Looper.myLooper(),
-                mTestSatelliteController, mTestImsManager,
-                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+                mTestSatelliteController, mTestImsManager);
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mPhone.isImsRegistered()).thenReturn(false);
@@ -149,7 +156,7 @@
     public void testTimeoutBeforeEmergencyCallEnd_T911() {
         testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
-                DEFAULT_HANDOVER_INTENT_ACTION);
+                DEFAULT_T911_HANDOVER_INTENT_ACTION);
     }
 
     @Test
@@ -267,7 +274,7 @@
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
-                DEFAULT_HANDOVER_INTENT_ACTION));
+                DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
         mTestSatelliteController.isOemEnabledSatelliteSupported = true;
@@ -331,7 +338,7 @@
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -380,7 +387,7 @@
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 4, 2);
@@ -419,7 +426,7 @@
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -505,8 +512,7 @@
         TestSOSMessageRecommender testSOSMessageRecommender = new TestSOSMessageRecommender(
                 mContext,
                 Looper.myLooper(),
-                satelliteController, mTestImsManager,
-                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+                satelliteController, mTestImsManager);
         testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
 
@@ -532,6 +538,32 @@
                 originalIsSatelliteViaOemProvisioned;
     }
 
+    @Test
+    public void testSelectEmergencyCallWaitForConnectionTimeoutDuration() {
+        // Both OEM and carrier don't support satellite
+        mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = false;
+        mTestSatelliteController.isOemEnabledSatelliteSupported = false;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(0, mTestSOSMessageRecommender.getTimeOutMillis());
+
+        // Only OEM support satellite
+        mTestSatelliteController.isOemEnabledSatelliteSupported = true;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+                mTestSOSMessageRecommender.getTimeOutMillis());
+
+        // Both OEM and carrier support satellite. Thus, carrier's timeout duration will be used
+        long carrierTimeoutMillis = 1000;
+        mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = true;
+        mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                carrierTimeoutMillis;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(carrierTimeoutMillis, mTestSOSMessageRecommender.getTimeOutMillis());
+    }
+
     private void testStopTrackingCallBeforeTimeout(
             @Connection.ConnectionState int connectionState) {
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
@@ -599,7 +631,7 @@
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -636,6 +668,9 @@
         private boolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = true;
         public boolean isOemEnabledSatelliteSupported = true;
         public boolean isCarrierEnabledSatelliteSupported = true;
+        public boolean isSatelliteEmergencyMessagingSupportedViaCarrier = true;
+        public long carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS;
 
         /**
          * Create a SatelliteController to act as a backend service of
@@ -696,6 +731,16 @@
             return INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
         }
 
+        @Override
+        public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
+            return isSatelliteEmergencyMessagingSupportedViaCarrier;
+        }
+
+        @Override
+        public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+            return carrierEmergencyCallWaitForConnectionTimeoutMillis;
+        }
+
         public void setSatelliteConnectedViaCarrierWithinHysteresisTime(
                 boolean connectedViaCarrier) {
             mIsSatelliteConnectedViaCarrierWithinHysteresisTime = connectedViaCarrier;
@@ -811,12 +856,10 @@
          * @param imsManager          The ImsManager instance associated with the phone, which is
          *                            used for making the emergency call. This argument is not
          *                            null only in unit tests.
-         * @param timeoutMillis       The timeout duration of the timer.
          */
         TestSOSMessageRecommender(Context context, Looper looper,
-                SatelliteController satelliteController, ImsManager imsManager,
-                long timeoutMillis) {
-            super(context, looper, satelliteController, imsManager, timeoutMillis);
+                SatelliteController satelliteController, ImsManager imsManager) {
+            super(context, looper, satelliteController, imsManager);
         }
 
         @Override
@@ -843,6 +886,10 @@
         public void sendServiceStateChangedEvent() {
             sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED));
         }
+
+        public long getTimeOutMillis() {
+            return mTimeoutMillis;
+        }
     }
 
     private static class TestConnection extends Connection {