Merge "AIDL IRadioModemIndication#onImeiMappingChanged() implementation for the change in the IMEI wrt sim slot" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 8d05a51..7bfa416 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -26,4 +26,11 @@
   namespace: "telephony"
   description: "Force networks that have PRIORITIZE_BANDWIDTH or PRIORITIZE_LATENCY to be metered."
   bug: "301310451"
+  }
+
+flag {
+  name: "slicing_additional_error_codes"
+  namespace: "telephony"
+  description: "Support additional slicing error codes and functionality."
+  bug: "307378699"
 }
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index 4f06049..0fa1f1e 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -12,4 +12,18 @@
     namespace: "telephony"
     description: "This flag ignores the incoming call by throwing an exception if the call was already terminated before the framework registers the listener for the incoming call"
     bug:"289461637"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "clear_cached_ims_phone_number_when_device_lost_ims_registration"
+    namespace: "telephony"
+    description: "This flag clears cached IMS phone number when device lost IMS registration"
+    bug:"288002989"
+}
+
+flag {
+    name: "update_ims_service_by_gathering_provisioning_changes"
+    namespace: "telephony"
+    description: "This flag is created to prevent unnecessary updates when multiple provisioning items to update ims service are changed."
+    bug:"302281114"
+}
diff --git a/flags/uicc.aconfig b/flags/uicc.aconfig
index 84e491e..3ef2301 100644
--- a/flags/uicc.aconfig
+++ b/flags/uicc.aconfig
@@ -1 +1,14 @@
-package: "com.android.internal.telephony.flags"
\ No newline at end of file
+package: "com.android.internal.telephony.flags"
+
+flag {
+    name: "esim_bootstrap_provisioning_flag"
+    namespace: "telephony"
+    description: "This flag controls eSIM Bootstrap provisioning feature support."
+    bug:"298567545"
+}
+flag {
+    name: "imsi_key_retry_download_on_phone_unlock"
+    namespace: "telephony"
+    description: "This flag controls to download the IMSI encryption keys after user unlocks the phone."
+    bug:"303780982"
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
index 195ef16..9143f21 100644
--- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
+++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
@@ -20,6 +20,7 @@
 
 import android.app.AlarmManager;
 import android.app.DownloadManager;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -40,6 +41,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -108,6 +110,7 @@
     private String mURL;
     private boolean mAllowedOverMeteredNetwork = false;
     private boolean mDeleteOldKeyAfterDownload = false;
+    private boolean mIsRequiredToHandleUnlock;
     private TelephonyManager mTelephonyManager;
     private UserManager mUserManager;
 
@@ -116,13 +119,16 @@
     public int mCarrierId;
     @VisibleForTesting
     public long mDownloadId;
+    private final FeatureFlags mFeatureFlags;
 
-    public CarrierKeyDownloadManager(Phone phone) {
+    public CarrierKeyDownloadManager(Phone phone, FeatureFlags featureFlags) {
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         mContext = phone.getContext();
         IntentFilter filter = new IntentFilter();
         filter.addAction(INTENT_KEY_RENEWAL_ALARM_PREFIX);
         filter.addAction(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
+        filter.addAction(Intent.ACTION_USER_PRESENT);
         mContext.registerReceiver(mBroadcastReceiver, filter, null, phone);
         mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
@@ -186,6 +192,16 @@
                     Log.d(LOG_TAG, "Handling reset intent: " + action);
                     sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
                 }
+            }  else if (action.equals(Intent.ACTION_USER_PRESENT)) {
+                // The Carrier key download fails when SIM is inserted while device is locked
+                // hence adding a retry logic when device is unlocked.
+                Log.d(LOG_TAG,
+                        "device unlocked, isRequiredToHandleUnlock = " + mIsRequiredToHandleUnlock
+                                + ", slotIndex = " + slotIndex);
+                if (mIsRequiredToHandleUnlock) {
+                    mIsRequiredToHandleUnlock = false;
+                    sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+                }
             }
         }
     };
@@ -224,6 +240,16 @@
                 // keys, we'll still want to renew the alarms, and try downloading the key a day
                 // later.
                 if (!downloadStartedSuccessfully) {
+                    // If download fails due to the device lock, we will reattempt once the device
+                    // is unlocked.
+                    if (mFeatureFlags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+                        KeyguardManager keyguardManager = mContext.getSystemService(
+                                KeyguardManager.class);
+                        if (keyguardManager.isKeyguardSecure()) {
+                            Log.e(LOG_TAG, "Key download failed in device lock state");
+                            mIsRequiredToHandleUnlock = true;
+                        }
+                    }
                     resetRenewalAlarm();
                 }
             } else {
@@ -233,6 +259,7 @@
             // delete any existing alarms.
             cleanupRenewalAlarms();
             mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId());
+
         }
     }
 
@@ -622,7 +649,8 @@
             mCarrierId = carrierId;
             mDownloadId = carrierKeyDownloadRequestId;
         } catch (Exception e) {
-            Log.e(LOG_TAG, "exception trying to download key from url: " + mURL);
+            Log.e(LOG_TAG, "exception trying to download key from url: " + mURL + ", Exception = "
+                    + e.getMessage());
             return false;
         }
         return true;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 0dd2bba..b5cc37b 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -511,7 +511,7 @@
         mContext.registerReceiver(mBroadcastReceiver, filter,
                 android.Manifest.permission.MODIFY_PHONE_STATE, null, Context.RECEIVER_EXPORTED);
 
-        mCDM = new CarrierKeyDownloadManager(this);
+        mCDM = new CarrierKeyDownloadManager(this, mFeatureFlags);
         mCIM = new CarrierInfoManager();
 
         mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null);
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 8b832dd..6e3e911 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.data.PhoneSwitcher;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.FeatureFlagsImpl;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsNrSaModeHandler;
 import com.android.internal.telephony.imsphone.ImsPhone;
@@ -382,8 +383,27 @@
         return new InboundSmsTracker(context, cursor, isCurrentFormat3gpp2);
     }
 
+    /**
+     * Create an ImsPhoneCallTracker.
+     *
+     * @param imsPhone imsphone
+     * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker
+     * @deprecated Use {@link #makeImsPhoneCallTracker(ImsPhone, FeatureFlags)} instead
+     */
     public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) {
-        return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector);
+        return makeImsPhoneCallTracker(imsPhone, new FeatureFlagsImpl());
+    }
+
+    /**
+     * Create a ims phone call tracker.
+     *
+     * @param imsPhone imsphone
+     * @param featureFlags feature flags
+     * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker
+     */
+    public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone,
+                                                       @NonNull FeatureFlags featureFlags) {
+        return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector, featureFlags);
     }
 
     public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) {
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index 0c5c9cb..4cf5ef9 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -2290,6 +2290,10 @@
             }
         }
 
+        if (mDataNetworkController.isEsimBootStrapProvisioningActivated()) {
+            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
         // If one of the capabilities are for special use, for example, IMS, CBS, then this
         // network should be restricted, regardless data is enabled or not.
         if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())
@@ -3318,7 +3322,8 @@
             TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);
             DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
                     .getDataProfileForNetworkRequest(networkRequest, targetNetworkType,
-                            mPhone.getServiceState().isUsingNonTerrestrialNetwork(), false);
+                            mPhone.getServiceState().isUsingNonTerrestrialNetwork(),
+                            mDataNetworkController.isEsimBootStrapProvisioningActivated(), false);
             // Some carriers have different profiles between cellular and IWLAN. We need to
             // dynamically switch profile, but only when those profiles have same APN name.
             if (dataProfile != null && dataProfile.getApnSetting() != null
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 2d91967..c29afa6 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -101,6 +101,8 @@
 import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.ims.ImsResolver;
+import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.telephony.Rlog;
 
@@ -1330,6 +1332,7 @@
                         .getDataProfileForNetworkRequest(requestList.getFirst(),
                                 TelephonyManager.NETWORK_TYPE_IWLAN,
                                 mServiceState.isUsingNonTerrestrialNetwork(),
+                                isEsimBootStrapProvisioningActivated(),
                                 false/*ignorePermanentFailure*/);
                 if (candidate != null && !dataNetwork.getDataProfile().equals(candidate)) {
                     logv("But skipped because found better data profile " + candidate
@@ -1494,7 +1497,8 @@
             evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
             evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest(
                     networkRequest, getDataNetworkType(transport),
-                    mServiceState.isUsingNonTerrestrialNetwork(), true));
+                    mServiceState.isUsingNonTerrestrialNetwork(),
+                    isEsimBootStrapProvisioningActivated(), true));
             networkRequest.setEvaluation(evaluation);
             log(evaluation.toString());
             return evaluation;
@@ -1653,6 +1657,7 @@
         DataProfile dataProfile = mDataProfileManager
                 .getDataProfileForNetworkRequest(networkRequest, networkType,
                         mServiceState.isUsingNonTerrestrialNetwork(),
+                        isEsimBootStrapProvisioningActivated(),
                         // If the evaluation is due to environmental changes, then we should ignore
                         // the permanent failure reached earlier.
                         reason.isConditionBased());
@@ -2272,6 +2277,22 @@
     }
 
     /**
+     * Check if the device is in eSIM bootstrap provisioning state.
+     *
+     * @return {@code true} if the device is under eSIM bootstrap provisioning.
+     */
+    public boolean isEsimBootStrapProvisioningActivated() {
+        if (!mFeatureFlags.esimBootstrapProvisioningFlag()) {
+            return false;
+        }
+
+        SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
+                .getSubscriptionInfoInternal(mPhone.getSubId());
+        return subInfo != null
+                && subInfo.getProfileClass() == SubscriptionManager.PROFILE_CLASS_PROVISIONING;
+    }
+
+    /**
      * Register for IMS feature registration state.
      *
      * @param subId The subscription index.
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index 273dc8b..df1fc92 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -255,6 +255,7 @@
         cursor.close();
         return dataProfile;
     }
+
     /**
      * Update all data profiles, including preferred data profile, and initial attach data profile.
      * Also send those profiles down to the modem if needed.
@@ -640,12 +641,12 @@
      */
     public @Nullable DataProfile getDataProfileForNetworkRequest(
             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
-            boolean isNtn, boolean ignorePermanentFailure) {
+            boolean isNtn, boolean isEsimBootstrapProvisioning, boolean ignorePermanentFailure) {
         ApnSetting apnSetting = null;
         if (networkRequest.hasAttribute(TelephonyNetworkRequest
                 .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
             apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, isNtn,
-                    ignorePermanentFailure);
+                    isEsimBootstrapProvisioning, ignorePermanentFailure);
         }
 
         TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
@@ -711,48 +712,52 @@
      */
     private @Nullable ApnSetting getApnSettingForNetworkRequest(
             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
-            boolean isNtn, boolean ignorePermanentFailure) {
+            boolean isNtn, boolean isEsimBootStrapProvisioning, boolean ignorePermanentFailure) {
         if (!networkRequest.hasAttribute(
                 TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
             loge("Network request does not have APN setting attribute.");
             return null;
         }
 
-        if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
-            // If the preferred data profile can be used, always use it if it can satisfy the
-            // network request with current network type (even though it's been marked as permanent
-            // failed.)
-            if (mPreferredDataProfile != null
-                    && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
-                    && mPreferredDataProfile.getApnSetting() != null
-                    && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)
-                    && ((isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
-                            ApnSetting.INFRASTRUCTURE_SATELLITE))
-                    || (!isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
-                            ApnSetting.INFRASTRUCTURE_CELLULAR)))) {
-                if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
-                        .getPermanentFailed()) {
-                    return mPreferredDataProfile.getApnSetting();
+        // if esim bootstrap provisioning in progress, do not apply preferred data profile
+        if (!isEsimBootStrapProvisioning) {
+            if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
+                // If the preferred data profile can be used, always use it if it can satisfy the
+                // network request with current network type (even though it's been marked as
+                // permanent failed.)
+                if (mPreferredDataProfile != null
+                        && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
+                        && mPreferredDataProfile.getApnSetting() != null
+                        && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)
+                        && ((isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
+                        ApnSetting.INFRASTRUCTURE_SATELLITE))
+                        || (!isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
+                        ApnSetting.INFRASTRUCTURE_CELLULAR)))) {
+                    if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
+                            .getPermanentFailed()) {
+                        return mPreferredDataProfile.getApnSetting();
+                    }
+                    log("The preferred data profile is permanently failed. Only condition based "
+                            + "retry can happen.");
+                    return null;
                 }
-                log("The preferred data profile is permanently failed. Only condition based "
-                        + "retry can happen.");
-                return null;
-            }
-        } else {
-            // If the preferred data profile can be used, always use it if it can satisfy the
-            // network request with current network type (even though it's been marked as permanent
-            // failed.)
-            if (mPreferredDataProfile != null
-                    && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
-                    && mPreferredDataProfile.getApnSetting() != null
-                    && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)) {
-                if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
-                        .getPermanentFailed()) {
-                    return mPreferredDataProfile.getApnSetting();
+            } else {
+                // If the preferred data profile can be used, always use it if it can satisfy the
+                // network request with current network type (even though it's been marked as
+                // permanent failed.)
+                if (mPreferredDataProfile != null
+                        && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
+                        && mPreferredDataProfile.getApnSetting() != null
+                        && mPreferredDataProfile.getApnSetting()
+                        .canSupportNetworkType(networkType)) {
+                    if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
+                            .getPermanentFailed()) {
+                        return mPreferredDataProfile.getApnSetting();
+                    }
+                    log("The preferred data profile is permanently failed. Only condition based "
+                            + "retry can happen.");
+                    return null;
                 }
-                log("The preferred data profile is permanently failed. Only condition based "
-                        + "retry can happen.");
-                return null;
             }
         }
 
@@ -778,6 +783,8 @@
                 .filter((dp) -> {
                     if (dp.getApnSetting() == null) return false;
                     if (!dp.getApnSetting().canSupportNetworkType(networkType)) return false;
+                    if (isEsimBootStrapProvisioning
+                            != dp.getApnSetting().isEsimBootstrapProvisioning()) return false;
                     if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
                         if (isNtn && !dp.getApnSetting().isForInfrastructure(
                                 ApnSetting.INFRASTRUCTURE_SATELLITE)) {
@@ -820,6 +827,10 @@
             return null;
         }
 
+        if (isEsimBootStrapProvisioning) {
+            log("Found esim bootstrap provisioning data profile for network request: "
+                    + dataProfiles.get(0).getApnSetting());
+        }
         return dataProfiles.get(0).getApnSetting();
     }
 
@@ -865,7 +876,9 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                         .build(), mPhone);
         return getDataProfileForNetworkRequest(networkRequest, networkType,
-                mPhone.getServiceState().isUsingNonTerrestrialNetwork(), true) != null;
+                mPhone.getServiceState().isUsingNonTerrestrialNetwork(),
+                mDataNetworkController.isEsimBootStrapProvisioningActivated(),
+                true) != null;
     }
 
     /**
@@ -1040,6 +1053,8 @@
         apnBuilder.setCarrierId(apn1.getCarrierId());
         apnBuilder.setSkip464Xlat(apn1.getSkip464Xlat());
         apnBuilder.setAlwaysOn(apn1.isAlwaysOn());
+        apnBuilder.setInfrastructureBitmask(apn1.getInfrastructureBitmask());
+        apnBuilder.setEsimBootstrapProvisioning(apn1.isEsimBootstrapProvisioning());
 
         return new DataProfile.Builder()
                 .setApnSetting(apnBuilder.build())
diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
index 5ef8b8a..f5cf950 100644
--- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
@@ -23,7 +23,11 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
+import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelectionService.EmergencyScanType;
@@ -32,12 +36,14 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.TransportSelectorCallback;
 import android.telephony.WwanSelectorCallback;
+import android.telephony.data.ApnSetting;
 import android.util.LocalLog;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.io.PrintWriter;
@@ -193,7 +199,12 @@
                             mController.getDomainSelectionServiceExecutor());
                     break;
                 case EVENT_QUALIFIED_NETWORKS_CHANGED:
-                    onQualifiedNetworksChanged();
+                    ar = (AsyncResult) msg.obj;
+                    if (ar == null || ar.result == null) {
+                        loge("handleMessage EVENT_QUALIFIED_NETWORKS_CHANGED null result");
+                        break;
+                    }
+                    onQualifiedNetworksChanged((List<QualifiedNetworks>) ar.result);
                     break;
                 default:
                     loge("handleMessage unexpected msg=" + msg.what);
@@ -473,7 +484,7 @@
     /**
      * Notifies the change of qualified networks.
      */
-    protected void onQualifiedNetworksChanged() {
+    protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) {
         if (mIsEmergency
                 && (mSelectorType == DomainSelectionService.SELECTOR_TYPE_CALLING)) {
             // DomainSelectionConnection for emergency calls shall override this.
@@ -483,6 +494,33 @@
     }
 
     /**
+     * Get the  preferred transport.
+     *
+     * @param apnType APN type.
+     * @return The preferred transport.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+    public int getPreferredTransport(@ApnType int apnType,
+            List<QualifiedNetworks> networksList) {
+        for (QualifiedNetworks networks : networksList) {
+            if (networks.qualifiedNetworks.length > 0) {
+                if (networks.apnType == apnType) {
+                    return getTransportFromAccessNetwork(networks.qualifiedNetworks[0]);
+                }
+            }
+        }
+
+        loge("getPreferredTransport no network found for " + ApnSetting.getApnTypeString(apnType));
+        return AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
+    }
+
+    private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) {
+        return accessNetwork == AccessNetworkType.IWLAN
+                ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+                : AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
+    }
+
+    /**
      * Dumps local log.
      */
     public void dump(@NonNull PrintWriter printWriter) {
diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java
index 5f3c3b6..c397788 100644
--- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java
@@ -40,8 +40,10 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.data.AccessNetworksManager;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -163,9 +165,8 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void onQualifiedNetworksChanged() {
-        AccessNetworksManager anm = mPhone.getAccessNetworksManager();
-        int preferredTransport = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY);
+    protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) {
+        int preferredTransport = getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList);
         logi("onQualifiedNetworksChanged preferred=" + mPreferredTransportType
                 + ", current=" + preferredTransport);
         if (preferredTransport == mPreferredTransportType) {
@@ -177,6 +178,7 @@
                     future.complete(DOMAIN_PS);
                 }
             }
+            AccessNetworksManager anm = mPhone.getAccessNetworksManager();
             anm.unregisterForQualifiedNetworksChanged(mHandler);
         }
     }
diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java
index efcdf11..b776e21 100644
--- a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java
@@ -28,8 +28,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.data.AccessNetworksManager;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 
+import java.util.List;
+
 /**
  * Manages the information of request and the callback binder for an emergency SMS.
  */
@@ -139,14 +142,14 @@
     }
 
     @Override
-    protected void onQualifiedNetworksChanged() {
-        AccessNetworksManager anm = mPhone.getAccessNetworksManager();
-        int preferredTransportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY);
+    protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) {
+        int preferredTransportType = getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList);
 
         synchronized (mLock) {
             if (preferredTransportType == mPreferredTransportType) {
                 mPreferredTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
                 super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true);
+                AccessNetworksManager anm = mPhone.getAccessNetworksManager();
                 anm.unregisterForQualifiedNetworksChanged(mHandler);
             }
         }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 23473d2..6773dca 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -130,6 +130,7 @@
     private boolean mIsInEcm;
     private boolean mIsTestEmergencyNumber;
     private Runnable mOnEcmExitCompleteRunnable;
+    private int mOngoingCallProperties;
 
     /** For emergency SMS */
     private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>();
@@ -447,6 +448,7 @@
             return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
         }
 
+        mOngoingCallProperties = 0;
         mCallEmergencyModeFuture = new CompletableFuture<>();
 
         if (mSmsPhone != null) {
@@ -487,6 +489,7 @@
 
         if (Objects.equals(mOngoingCallId, callId)) {
             mOngoingCallId = null;
+            mOngoingCallProperties = 0;
         }
 
         if (wasActive && mActiveEmergencyCalls.isEmpty()
@@ -520,6 +523,7 @@
         mIsEmergencyCallStartedDuringEmergencySms = false;
         mCallEmergencyModeFuture = null;
         mOngoingCallId = null;
+        mOngoingCallProperties = 0;
         mPhone = null;
     }
 
@@ -757,10 +761,36 @@
     public void onEmergencyCallStateChanged(Call.State state, String callId) {
         if (state == Call.State.ACTIVE) {
             mActiveEmergencyCalls.add(callId);
+            if (Objects.equals(mOngoingCallId, callId)) {
+                Rlog.i(TAG, "call connected " + callId);
+                if (mPhone != null
+                        && isVoWiFi(mOngoingCallProperties)
+                        && mEmergencyMode == EmergencyConstants.MODE_EMERGENCY_WLAN) {
+                    // Recover normal service in cellular when VoWiFi is connected
+                    mPhone.cancelEmergencyNetworkScan(true, null);
+                }
+            }
         }
     }
 
     /**
+     * Handles the change of emergency call properties.
+     *
+     * @param properties the new call properties.
+     * @param callId the callId whose state has changed.
+     */
+    public void onEmergencyCallPropertiesChanged(int properties, String callId) {
+        if (Objects.equals(mOngoingCallId, callId)) {
+            mOngoingCallProperties = properties;
+        }
+    }
+
+    private static boolean isVoWiFi(int properties) {
+        return (properties & android.telecom.Connection.PROPERTY_WIFI) > 0
+                || (properties & android.telecom.Connection.PROPERTY_CROSS_SIM) > 0;
+    }
+
+    /**
      * Returns {@code true} if device and carrier support emergency callback mode.
      */
     @VisibleForTesting
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 3a93f18..1ee8447 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -47,6 +47,7 @@
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE;
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.Notification;
@@ -121,6 +122,7 @@
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.metrics.ImsStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
@@ -482,7 +484,7 @@
                         .inject(ImsNrSaModeHandler.class.getName())
                         .makeImsNrSaModeHandler(this);
         mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName())
-                .makeImsPhoneCallTracker(this);
+                .makeImsPhoneCallTracker(this, featureFlags);
         mCT.registerPhoneStateListener(mExternalCallTracker);
         mExternalCallTracker.setCallPuller(mCT);
 
@@ -2530,9 +2532,11 @@
             updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED,
                     imsRadioTech, suggestedModemAction);
 
-            // Clear the phone number from P-Associated-Uri
-            setCurrentSubscriberUris(null);
-            clearPhoneNumberForSourceIms();
+            if (mFeatureFlags.clearCachedImsPhoneNumberWhenDeviceLostImsRegistration()) {
+                // Clear the phone number from P-Associated-Uri
+                setCurrentSubscriberUris(null);
+                clearPhoneNumberForSourceIms();
+            }
         }
 
         @Override
@@ -2545,6 +2549,7 @@
 
     /** Clear the IMS phone number from IMS associated Uris when IMS registration is lost. */
     @VisibleForTesting
+    @FlaggedApi(Flags.FLAG_CLEAR_CACHED_IMS_PHONE_NUMBER_WHEN_DEVICE_LOST_IMS_REGISTRATION)
     public void clearPhoneNumberForSourceIms() {
         int subId = getSubId();
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index c3ee0f6..4f9b69d 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -148,6 +148,7 @@
 import com.android.internal.telephony.domainselection.DomainSelectionResolver;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs;
 import com.android.internal.telephony.metrics.CallQualityMetrics;
@@ -664,6 +665,7 @@
     private static final int EVENT_START_IMS_TRAFFIC_DONE = 33;
     private static final int EVENT_CONNECTION_SETUP_FAILURE = 34;
     private static final int EVENT_NEW_ACTIVE_CALL_STARTED = 35;
+    private static final int EVENT_PROVISIONING_CHANGED = 36;
 
     private static final int TIMEOUT_HANGUP_PENDINGMO = 500;
 
@@ -673,6 +675,8 @@
 
     private static final int TIMEOUT_PARTICIPANT_CONNECT_TIME_CACHE_MS = 60000; //ms
 
+    private static final int DELAY_STACKING_PROVISIONING_CHANGES_MILLIS = 50; //ms
+
     // Following values are for mHoldSwitchingState
     private enum HoldSwapState {
         // Not in the middle of a hold/swap operation
@@ -1235,17 +1239,39 @@
         }
     }
 
+    private final ConcurrentLinkedQueue<ProvisioningItem> mProvisioningItemQueue =
+            new ConcurrentLinkedQueue<>();
+
+    private static class ProvisioningItem {
+        final int mItem;
+        final Object mValue;
+        ProvisioningItem(int item, int value) {
+            this.mItem = item;
+            this.mValue = Integer.valueOf(value);
+        }
+
+        ProvisioningItem(int item, String value) {
+            this.mItem = item;
+            this.mValue = value;
+        }
+    }
+
+    private @NonNull final FeatureFlags mFeatureFlags;
+
     //***** Events
 
 
     //***** Constructors
-    public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory) {
-        this(phone, factory, phone.getContext().getMainExecutor());
+    public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory,
+            FeatureFlags featureFlags) {
+        this(phone, factory, phone.getContext().getMainExecutor(), featureFlags);
     }
 
     @VisibleForTesting
-    public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory, Executor executor) {
+    public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory, Executor executor,
+            FeatureFlags featureFlags) {
         this.mPhone = phone;
+        mFeatureFlags = featureFlags;
         mConnectorFactory = factory;
         if (executor != null) {
             mExecutor = executor;
@@ -4590,37 +4616,67 @@
 
     private final ProvisioningManager.Callback mConfigCallback =
             new ProvisioningManager.Callback() {
-        @Override
-        public void onProvisioningIntChanged(int item, int value) {
-            sendConfigChangedIntent(item, Integer.toString(value));
-            if ((mImsManager != null)
-                    && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
-                    || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
-                    || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) {
-                // Update Ims Service state to make sure updated provisioning values take effect
-                // immediately.
-                updateImsServiceConfig();
-            }
-        }
+                @Override
+                public void onProvisioningIntChanged(int item, int value) {
+                    // if updateImsServiceByGatheringProvisioningChanges feature is enabled,
+                    // Provisioning items are processed all at once by queuing and sending message.
+                    if (mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) {
+                        queueAndSendProvisioningChanged(new ProvisioningItem(item, value));
+                        return;
+                    }
+                    // run belows when updateImsServiceByGatheringProvisioningChanges feature is
+                    // disabled only
 
-        @Override
-        public void onProvisioningStringChanged(int item, String value) {
-            sendConfigChangedIntent(item, value);
-        }
+                    sendConfigChangedIntent(item, Integer.toString(value));
+                    if ((mImsManager != null)
+                            && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
+                            || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
+                            || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) {
+                        // Update Ims Service state to make sure updated provisioning values take
+                        // effect immediately.
+                        updateImsServiceConfig();
+                    }
+                }
 
-        // send IMS_CONFIG_CHANGED intent for older services that do not implement the new callback
-        // interface.
-        private void sendConfigChangedIntent(int item, String value) {
-            log("sendConfigChangedIntent - [" + item + ", " + value + "]");
-            Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
-            configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
-            configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
-            if (mPhone != null && mPhone.getContext() != null) {
-                mPhone.getContext().sendBroadcast(
-                        configChangedIntent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
-            }
-        }
-    };
+                @Override
+                public void onProvisioningStringChanged(int item, String value) {
+                    if (mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) {
+                        queueAndSendProvisioningChanged(new ProvisioningItem(item, value));
+                        return;
+                    }
+                    // run belows when updateImsServiceByGatheringProvisioningChanges feature is
+                    // disabled only
+
+                    sendConfigChangedIntent(item, value);
+                }
+
+                // send IMS_CONFIG_CHANGED intent for older services that do not implement the new
+                // callback interface.
+                private void sendConfigChangedIntent(int item, String value) {
+                    log("sendConfigChangedIntent - [" + item + ", " + value + "]");
+                    Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
+                    configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
+                    configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
+                    if (mPhone != null && mPhone.getContext() != null) {
+                        mPhone.getContext().sendBroadcast(configChangedIntent,
+                                Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+                    }
+                }
+
+                private void queueAndSendProvisioningChanged(ProvisioningItem provisioningItem) {
+                    if (!mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) {
+                        return;
+                    }
+
+                    boolean bQueueOffer = mProvisioningItemQueue.offer(provisioningItem);
+                    // Checks the Handler Message Queue and schedules a new message with small delay
+                    // to avoid stacking multiple redundant event only if it doesn't exist.
+                    if (bQueueOffer && !hasMessages(EVENT_PROVISIONING_CHANGED)) {
+                        sendMessageDelayed(obtainMessage(EVENT_PROVISIONING_CHANGED),
+                                DELAY_STACKING_PROVISIONING_CHANGES_MILLIS);
+                    }
+                }
+            };
 
     public void sendCallStartFailedDisconnect(ImsCall imsCall, ImsReasonInfo reasonInfo) {
         mPendingMO = null;
@@ -5011,6 +5067,11 @@
                 }
                 break;
             }
+
+            case EVENT_PROVISIONING_CHANGED: {
+                handleProvisioningChanged();
+                break;
+            }
         }
     }
 
@@ -6210,4 +6271,47 @@
         mImsTrafficSessions.forEachKey(1, token -> mPhone.stopImsTraffic(token, null));
         mImsTrafficSessions.clear();
     }
+
+    /**
+     * Process provisioning changes all at once.
+     */
+    private void handleProvisioningChanged() {
+        boolean bNeedUpdateImsServiceConfig = false;
+        ProvisioningItem provisioningItem;
+        while ((provisioningItem = mProvisioningItemQueue.poll()) != null) {
+            int item = provisioningItem.mItem;
+            if (provisioningItem.mValue instanceof Integer) {
+                sendConfigChangedIntent(item, provisioningItem.mValue.toString());
+                if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
+                        || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
+                        || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED) {
+                    bNeedUpdateImsServiceConfig = true;
+                }
+            } else if (provisioningItem.mValue instanceof String) {
+                sendConfigChangedIntent(item, provisioningItem.mValue.toString());
+            }
+        }
+        if (bNeedUpdateImsServiceConfig) {
+            // Update Ims Service state to make sure updated provisioning values take effect.
+            updateImsServiceConfig();
+        }
+    }
+
+    /**
+     * send IMS_CONFIG_CHANGED intent for older services that do not implement the new callback
+     * interface
+     *
+     * @param item provisioning item
+     * @param value provisioning value
+     */
+    private void sendConfigChangedIntent(int item, String value) {
+        log("sendConfigChangedIntent - [" + item + ", " + value + "]");
+        Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
+        configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
+        configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
+        if (mPhone != null && mPhone.getContext() != null) {
+            mPhone.getContext().sendBroadcast(
+                    configChangedIntent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index fc433f0..5148ecb 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -1300,6 +1300,7 @@
      */
     public boolean isSatelliteEnabled() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isSatelliteEnabled: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mIsSatelliteEnabled == null) return false;
@@ -1333,6 +1334,7 @@
      */
     public boolean isDemoModeEnabled() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isDemoModeEnabled: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mIsDemoModeEnabled;
@@ -1347,6 +1349,7 @@
      */
     public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("requestIsSatelliteSupported: oemEnabledSatelliteFlag is disabled");
             result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
             return;
         }
@@ -1558,6 +1561,8 @@
     public void unregisterForSatelliteProvisionStateChanged(
             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteProvisionStateChanged: "
+                    + "oemEnabledSatelliteFlag is disabled");
             return;
         }
         mSatelliteProvisionStateChangedListeners.remove(callback.asBinder());
@@ -1602,6 +1607,7 @@
     @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(int subId,
             @NonNull ISatelliteStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled");
             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
         }
         if (mSatelliteSessionController != null) {
@@ -1625,6 +1631,7 @@
     public void unregisterForSatelliteModemStateChanged(int subId,
             @NonNull ISatelliteStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (mSatelliteSessionController != null) {
@@ -1646,6 +1653,7 @@
     @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForSatelliteDatagram: oemEnabledSatelliteFlag is disabled");
             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
         }
         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -1665,6 +1673,7 @@
     public void unregisterForSatelliteDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteDatagram: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -1779,6 +1788,7 @@
      */
     public void setDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setDeviceAlignedWithSatellite: oemEnabledSatelliteFlag is disabled");
             return;
         }
         mDatagramController.setDeviceAlignedWithSatellite(isAligned);
@@ -1871,6 +1881,8 @@
      */
     @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSatelliteAttachRestrictionReasonsForCarrier: carrierEnabledSatelliteFlag is "
+                    + "disabled");
             return new HashSet<>();
         }
         synchronized (mIsSatelliteEnabledLock) {
@@ -1961,9 +1973,13 @@
      */
     public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteServicePackageName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
-        if (!isMockModemAllowed()) return false;
+        if (!isMockModemAllowed()) {
+            logd("setSatelliteServicePackageName: mock modem not allowed");
+            return false;
+        }
 
         // Cached states need to be cleared whenever switching satellite vendor services.
         logd("setSatelliteServicePackageName: Resetting cached states");
@@ -1993,6 +2009,7 @@
      */
     public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteListeningTimeoutDuration: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mSatelliteSessionController == null) {
@@ -2011,6 +2028,7 @@
      */
     public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteDeviceAlignedTimeoutDuration: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis);
@@ -2025,6 +2043,7 @@
      */
     public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteGatewayServicePackageName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mSatelliteSessionController == null) {
@@ -2046,6 +2065,7 @@
     public boolean setSatellitePointingUiClassName(
             @Nullable String packageName, @Nullable String className) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatellitePointingUiClassName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mPointingAppController.setSatellitePointingUiClassName(packageName, className);
@@ -2065,6 +2085,7 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public void onSatelliteServiceConnected() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("onSatelliteServiceConnected: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -2115,6 +2136,7 @@
      */
     public boolean isSatelliteSupported() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isSatelliteSupported: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         Boolean supported = isSatelliteSupportedInternal();
@@ -2128,6 +2150,7 @@
     @NonNull
     public List<String> getSatellitePlmnList(int subId) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSatellitePlmnList: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
         synchronized (mSupportedSatelliteServicesLock) {
@@ -2148,6 +2171,7 @@
     @NonNull
     public List<Integer> getSupportedSatelliteServices(int subId, String plmn) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSupportedSatelliteServices: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
         synchronized (mSupportedSatelliteServicesLock) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 62f7371..dc6ea13 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -30,6 +30,8 @@
 import android.os.Message;
 import android.os.RegistrantList;
 import android.os.RemoteException;
+import android.telephony.IBooleanConsumer;
+import android.telephony.IIntegerConsumer;
 import android.telephony.Rlog;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
@@ -47,8 +49,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.ExponentialBackoff;
-import com.android.internal.telephony.IBooleanConsumer;
-import com.android.internal.telephony.IIntegerConsumer;
 
 import java.util.Arrays;
 import java.util.List;
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 80ec039..8146983 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.compat.CompatChanges;
@@ -44,9 +45,11 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.TelephonyServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Telephony.SimInfo;
 import android.service.carrier.CarrierIdentifier;
@@ -96,6 +99,7 @@
 import com.android.internal.telephony.data.PhoneSwitcher;
 import com.android.internal.telephony.euicc.EuiccController;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccUtils;
@@ -123,6 +127,7 @@
 import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 /**
  * The subscription manager service is the backend service of {@link SubscriptionManager}.
@@ -130,6 +135,8 @@
  */
 public class SubscriptionManagerService extends ISub.Stub {
     private static final String LOG_TAG = "SMSVC";
+    private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
+    private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem";
 
     /** Whether enabling verbose debugging message or not. */
     private static final boolean VDBG = false;
@@ -188,6 +195,18 @@
     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
     public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L;
 
+    /**
+     * Apps targeting on Android V and beyond can only see subscriptions accessible by them
+     * according to its user Id.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public static final long FILTER_ACCESSIBLE_SUBS_BY_USER = 296076674L;
+
+    /** Wrap Binder methods for testing. */
+    @NonNull
+    private static final BinderWrapper BINDER_WRAPPER = new BinderWrapper();
+
     /** Instance of subscription manager service. */
     @NonNull
     private static SubscriptionManagerService sInstance;
@@ -284,6 +303,12 @@
     private final int[] mSimState;
 
     /**
+     * {@code true} if a user profile can only see the SIMs associated with it, unless it possesses
+     * no SIMs on the device.
+     */
+    private Map<Integer, List<Integer>> mUserIdToAvailableSubs = new ConcurrentHashMap<>();
+
+    /**
      * Slot index/subscription map that automatically invalidate cache in
      * {@link SubscriptionManager}.
      *
@@ -356,6 +381,14 @@
         }
     }
 
+    /** Binder Wrapper for test mocking. */
+    @VisibleForTesting
+    public static class BinderWrapper {
+        @NonNull public UserHandle getCallingUserHandle() {
+            return Binder.getCallingUserHandle();
+        }
+    }
+
     /**
      * This is the callback used for listening events from {@link SubscriptionManagerService}.
      */
@@ -510,6 +543,8 @@
                      */
                     @Override
                     public void onSubscriptionChanged(int subId) {
+                        updateUserIdToAvailableSubs();
+
                         mSubscriptionManagerServiceCallbacks.forEach(
                                 callback -> callback.invokeFromExecutor(
                                         () -> callback.onSubscriptionChanged(subId)));
@@ -1145,6 +1180,8 @@
                         if (mFeatureFlags.oemEnabledSatelliteFlag()) {
                             builder.setOnlyNonTerrestrialNetwork(
                                     isSatellitePlmn(mcc + mnc) ? 1 : 0);
+                        } else {
+                            log("updateEmbeddedSubscriptions: oemEnabledSatelliteFlag is disabled");
                         }
                     }
                     // If cardId = unsupported or un-initialized, we have no reason to update DB.
@@ -1460,8 +1497,11 @@
                         loge("updateSubscription: ICC card is not available.");
                     }
 
-                    // Clear the cached Ims phone number before proceeding with Ims Registration
-                    setNumberFromIms(subId, new String(""));
+                    if (Flags.clearCachedImsPhoneNumberWhenDeviceLostImsRegistration()) {
+                        // Clear the cached Ims phone number
+                        // before proceeding with Ims Registration
+                        setNumberFromIms(subId, new String(""));
+                    }
 
                     // Attempt to restore SIM specific settings when SIM is loaded.
                     Bundle result = mContext.getContentResolver().call(
@@ -1654,7 +1694,8 @@
     }
 
     /**
-     * Get all subscription info records from SIMs that are inserted now or previously inserted.
+     * Get all subscription info records from SIMs visible to the calling user that are inserted now
+     * or previously inserted.
      *
      * <p>
      * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission,
@@ -1694,8 +1735,7 @@
             throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or "
                     + "carrier privilege");
         }
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full
                 // list. Carrier apps can only get the subscriptions they have privileged.
                 .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(
@@ -1824,8 +1864,8 @@
     }
 
     /**
-     * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted
-     * by {@link SubscriptionInfo#getSimSlotIndex} then by
+     * Get the SubscriptionInfo(s) of the active subscriptions for calling user. The records will be
+     * sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
      * {@link SubscriptionInfo#getSubscriptionId}.
      *
      * @param callingPackage The package making the call.
@@ -1848,7 +1888,7 @@
         // on the subs it has carrier privilege.
         if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext,
                 Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId,
-                "getAllSubInfoList")) {
+                "getActiveSubscriptionInfoList")) {
             // Ideally we should avoid silent failure, but since this API has already been used by
             // many apps and they do not expect the security exception, we return an empty list
             // here so it's consistent with pre-U behavior.
@@ -1856,14 +1896,13 @@
                     + "permission. Returning empty list here.");
             return Collections.emptyList();
         }
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 .filter(SubscriptionInfoInternal::isActive)
                 // Remove the identifier if the caller does not have sufficient permission.
                 // carrier apps will get full subscription info on the subscriptions associated
                 // to them.
                 .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(),
-                        callingPackage, callingFeatureId, "getAllSubInfoList"))
+                        callingPackage, callingFeatureId, "getActiveSubscriptionInfoList"))
                 .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex)
                         .thenComparing(SubscriptionInfo::getSubscriptionId))
                 .collect(Collectors.toList());
@@ -1893,13 +1932,7 @@
             throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or "
                     + "carrier privilege");
         }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return getActiveSubIdList(false).length;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        return getActiveSubIdListAsUser(false, BINDER_WRAPPER.getCallingUserHandle()).length;
     }
 
     /**
@@ -1930,27 +1963,42 @@
             @Nullable String callingFeatureId) {
         enforcePermissions("getAvailableSubscriptionInfoList",
                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        return getAvailableSubscriptionsInternalStream()
+                .sorted(Comparator.comparing(SubscriptionInfoInternal::getSimSlotIndex)
+                        .thenComparing(SubscriptionInfoInternal::getSubscriptionId))
+                .map(SubscriptionInfoInternal::toSubscriptionInfo)
+                .collect(Collectors.toList());
 
-        // Now that all security checks pass, perform the operation as ourselves.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if
-            // they are in inactive slot or programmatically disabled, they are still considered
-            // available. In this case we get their iccid from slot info and include their
-            // subscriptionInfos.
-            List<String> iccIds = getIccIdsOfInsertedPhysicalSims();
+    }
 
-            return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
-                    .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId())
-                            || (mEuiccManager != null && mEuiccManager.isEnabled()
-                            && subInfo.isEmbedded()))
-                    .map(SubscriptionInfoInternal::toSubscriptionInfo)
-                    .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex)
-                            .thenComparing(SubscriptionInfo::getSubscriptionId))
-                    .collect(Collectors.toList());
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+    /**
+     * @return all the subscriptions visible to user on the device.
+     */
+    private Stream<SubscriptionInfoInternal> getAvailableSubscriptionsInternalStream() {
+        // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if
+        // they are in inactive slot or programmatically disabled, they are still considered
+        // available. In this case we get their iccid from slot info and include their
+        // subscriptionInfos.
+        List<String> iccIds = getIccIdsOfInsertedPhysicalSims();
+
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId())
+                        || (mEuiccManager != null && mEuiccManager.isEnabled()
+                        && subInfo.isEmbedded()));
+    }
+
+    /**
+     * Tracks for each user Id, a list of subscriptions associated with it.
+     * A profile is barred from seeing unassociated subscriptions if it has its own subscription
+     * which is available to choose from the device.
+     */
+    private void updateUserIdToAvailableSubs() {
+        mUserIdToAvailableSubs = getAvailableSubscriptionsInternalStream()
+                .collect(Collectors.groupingBy(
+                        SubscriptionInfoInternal::getUserId,
+                        Collectors.mapping(SubscriptionInfoInternal::getSubscriptionId,
+                                Collectors.toList())));
+        log("updateUserIdToAvailableSubs: " + mUserIdToAvailableSubs);
     }
 
     /**
@@ -1985,8 +2033,7 @@
 
         // Verify that the callingPackage belongs to the calling UID
         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 .map(SubscriptionInfoInternal::toSubscriptionInfo)
                 .filter(subInfo -> subInfo.isEmbedded()
                         && mSubscriptionManager.canManageSubscription(subInfo, callingPackage))
@@ -2777,10 +2824,37 @@
 
     /**
      * @return The default subscription id.
+     * @deprecated Use {@link #getDefaultSubIdAsUser}.
      */
     @Override
     public int getDefaultSubId() {
-        return mDefaultSubId.get();
+        return getDefaultSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * @param userId The given user Id to check.
+     * @return The default subscription id.
+     */
+    @Override
+    public int getDefaultSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultSubId.get());
+    }
+
+    /**
+     * Get the default subscription visible to the caller.
+     * @param userId The calling user Id.
+     * @param defaultValue Useful if the user owns more than one subscription.
+     * @return The subscription Id default to use.
+     */
+    private int getDefaultAsUser(@UserIdInt int userId, int defaultValue) {
+        List<SubscriptionInfoInternal> subInfos =
+                getSubscriptionInfoStreamAsUser(UserHandle.of(userId))
+                        .filter(SubscriptionInfoInternal::isActive)
+                        .toList();
+        if (subInfos.size() == 1) {
+            return subInfos.get(0).getSubscriptionId();
+        }
+        return defaultValue;
     }
 
     /**
@@ -2872,10 +2946,20 @@
 
     /**
      * @return The default subscription id for voice.
+     * @deprecated Use {@link #getDefaultVoiceSubIdAsUser}.
      */
     @Override
     public int getDefaultVoiceSubId() {
-        return mDefaultVoiceSubId.get();
+        return getDefaultVoiceSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * @param userId The calling user Id.
+     * @return The default voice subscription id.
+     */
+    @Override
+    public int getDefaultVoiceSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultVoiceSubId.get());
     }
 
     /**
@@ -2918,10 +3002,24 @@
 
     /**
      * @return The default subscription id for SMS.
+     * @deprecated Use {@link #getDefaultSmsSubIdAsUser}.
      */
     @Override
     public int getDefaultSmsSubId() {
-        return mDefaultSmsSubId.get();
+        return getDefaultSmsSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * Get the default sms subscription id associated with the user. When a subscription is
+     * associated with personal profile or work profile, the default sms subscription id will be
+     * always the subscription it is associated with.
+     *
+     * @param userId The given user Id to check.
+     * @return The default voice id.
+     */
+    @Override
+    public int getDefaultSmsSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultSmsSubId.get());
     }
 
     /**
@@ -2978,19 +3076,30 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public int[] getActiveSubIdList(boolean visibleOnly) {
         enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        // UserHandle.ALL because this API is exposed as system API.
+        return getActiveSubIdListAsUser(visibleOnly, UserHandle.ALL);
+    }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return mSlotIndexToSubId.values().stream()
-                    .filter(subId -> {
-                        SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
-                                .getSubscriptionInfoInternal(subId);
-                        return subInfo != null && (!visibleOnly || subInfo.isVisible()); })
-                    .mapToInt(x -> x)
-                    .toArray();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+    /**
+     * Get the active subscription id list as user.
+     * Must be used before clear Binder identity.
+     *
+     * @param visibleOnly {@code true} if only includes user visible subscription's sub id.
+     * @param user If {@code null}, uses the calling user handle to judge which subscriptions are
+     *             accessible to the caller.
+     * @return List of the active subscription id.
+     */
+    private int[] getActiveSubIdListAsUser(boolean visibleOnly, @NonNull final UserHandle user) {
+        return mSlotIndexToSubId.values().stream()
+                .filter(subId -> {
+                    SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
+                            .getSubscriptionInfoInternal(subId);
+                    return subInfo != null && (!visibleOnly || subInfo.isVisible())
+                            && isSubscriptionAssociatedWithUserInternal(
+                                    subInfo, user.getIdentifier());
+                })
+                .mapToInt(x -> x)
+                .toArray();
     }
 
     /**
@@ -3654,26 +3763,28 @@
             @NonNull UserHandle userHandle) {
         enforcePermissions("isSubscriptionAssociatedWithUser",
                 Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        SubscriptionInfoInternal subInfoInternal = mSubscriptionDatabaseManager
+                .getSubscriptionInfoInternal(subscriptionId);
+        // Throw IAE if no record of the sub's association state.
+        if (subInfoInternal == null) {
+            throw new IllegalArgumentException(
+                    "[isSubscriptionAssociatedWithUser]: Subscription doesn't exist: "
+                            + subscriptionId);
+        }
+
+        if (mFeatureFlags.workProfileApiSplit()) {
+            return isSubscriptionAssociatedWithUserInternal(
+                    subInfoInternal, userHandle.getIdentifier());
+        }
 
         long token = Binder.clearCallingIdentity();
         try {
-            // Throw IAE if no record of the sub's association state.
-            if (mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subscriptionId) == null) {
-                throw new IllegalArgumentException(
-                        "[isSubscriptionAssociatedWithUser]: Subscription doesn't exist: "
-                                + subscriptionId);
-            }
-
             // Get list of subscriptions associated with this user.
             List<SubscriptionInfo> associatedSubscriptionsList =
                     getSubscriptionInfoListAssociatedWithUser(userHandle);
-            if (associatedSubscriptionsList.isEmpty()) {
-                return false;
-            }
-
             // Return true if required subscription is present in associated subscriptions list.
             for (SubscriptionInfo subInfo: associatedSubscriptionsList) {
-                if (subInfo.getSubscriptionId() == subscriptionId){
+                if (subInfo.getSubscriptionId() == subscriptionId) {
                     return true;
                 }
             }
@@ -3684,6 +3795,25 @@
     }
 
     /**
+     * @param subInfo The subscription info to check.
+     * @param userId The caller user Id.
+     * @return {@code true} if the given user Id is allowed to access to the given subscription.
+     */
+    private boolean isSubscriptionAssociatedWithUserInternal(
+            @NonNull SubscriptionInfoInternal subInfo, @UserIdInt int userId) {
+        if (!mFeatureFlags.workProfileApiSplit()
+                || !CompatChanges.isChangeEnabled(FILTER_ACCESSIBLE_SUBS_BY_USER,
+                Binder.getCallingUid())) {
+            return true;
+        }
+        return subInfo.getUserId() == userId
+                // Can access the unassociated sub if the user doesn't have its own.
+                || (subInfo.getUserId() == UserHandle.USER_NULL
+                && mUserIdToAvailableSubs.get(userId) == null)
+                || userId == UserHandle.USER_ALL;
+    }
+
+    /**
      * Get list of subscriptions associated with user.
      *
      * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser
@@ -3696,11 +3826,18 @@
      *
      */
     @Override
-    public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
+    @NonNull
+    public List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
             @NonNull UserHandle userHandle) {
         enforcePermissions("getSubscriptionInfoListAssociatedWithUser",
                 Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
 
+        if (mFeatureFlags.workProfileApiSplit()) {
+            return getSubscriptionInfoStreamAsUser(userHandle)
+                    .map(SubscriptionInfoInternal::toSubscriptionInfo)
+                    .collect(Collectors.toList());
+        }
+
         long token = Binder.clearCallingIdentity();
         try {
             List<SubscriptionInfoInternal> subInfoList =  mSubscriptionDatabaseManager
@@ -3724,20 +3861,45 @@
             UserManager userManager = mContext.getSystemService(UserManager.class);
             if ((userManager != null)
                     && (userManager.isManagedProfile(userHandle.getIdentifier()))) {
-                // For work profile, return subscriptions associated only with work profile
+                // For work profile, return subscriptions associated only with work profile even
+                // if it's empty.
                 return subscriptionsAssociatedWithUser;
             }
 
-            // For all other profiles, if subscriptionsAssociatedWithUser is empty return all the
-            // subscriptionsWithNoAssociation.
-            return subscriptionsAssociatedWithUser.isEmpty() ?
-                    subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
+            // For all other profiles, if subscriptionsAssociatedWithUser is empty return all
+            // the subscriptionsWithNoAssociation.
+            return subscriptionsAssociatedWithUser.isEmpty()
+                    ? subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
     /**
+     * @return All active subscriptions.
+     */
+    @NonNull
+    private List<SubscriptionInfoInternal> getActiveSubscriptionInfoListAllUser() {
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(SubscriptionInfoInternal::isActive)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Get subscriptions accessible to the caller user.
+     *
+     * @param user The user to check.
+     * @return a stream of accessible internal subscriptions.
+     */
+    @NonNull
+    private Stream<SubscriptionInfoInternal> getSubscriptionInfoStreamAsUser(
+            @NonNull final UserHandle user) {
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(info -> isSubscriptionAssociatedWithUserInternal(
+                        info, user.getIdentifier()));
+    }
+
+    /**
      * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
      * configs to device for all existing SIMs in the subscription database {@link SimInfo}.
      * Internally, it will store the backup data in an internal file. This file will persist on
@@ -3804,14 +3966,26 @@
      * @throws SecurityException if the caller does not have any permissions.
      */
     private void enforcePermissions(@Nullable String message, @NonNull String ...permissions) {
+        if (!hasPermissions(permissions)) {
+            throw new SecurityException(
+                    message + ". Does not have any of the following permissions. "
+                            + Arrays.toString(permissions));
+        }
+    }
+
+    /**
+     * Check have any of the permissions
+     * @param permissions The permissions to check.
+     * @return {@code true} if the caller has one of the given permissions.
+     */
+    private boolean hasPermissions(@NonNull String ...permissions) {
         for (String permission : permissions) {
             if (mContext.checkCallingOrSelfPermission(permission)
                     == PackageManager.PERMISSION_GRANTED) {
-                return;
+                return true;
             }
         }
-        throw new SecurityException(message + ". Does not have any of the following permissions. "
-                + Arrays.toString(permissions));
+        return false;
     }
 
     /**
@@ -3835,9 +4009,8 @@
      */
     @Nullable
     public SubscriptionInfo getSubscriptionInfo(int subId) {
-        SubscriptionInfoInternal subscriptionInfoInternal = getSubscriptionInfoInternal(subId);
-        return subscriptionInfoInternal != null
-                ? subscriptionInfoInternal.toSubscriptionInfo() : null;
+        SubscriptionInfoInternal infoInternal = getSubscriptionInfoInternal(subId);
+        return infoInternal != null ? infoInternal.toSubscriptionInfo() : null;
     }
 
     /**
@@ -3954,8 +4127,7 @@
      */
     @VisibleForTesting
     public void updateGroupDisabled() {
-        List<SubscriptionInfo> activeSubscriptions = getActiveSubscriptionInfoList(
-                mContext.getOpPackageName(), mContext.getFeatureId());
+        List<SubscriptionInfoInternal> activeSubscriptions = getActiveSubscriptionInfoListAllUser();
         for (SubscriptionInfo oppSubInfo : getOpportunisticSubscriptions(
                 mContext.getOpPackageName(), mContext.getFeatureId())) {
             boolean groupDisabled = activeSubscriptions.stream()
@@ -3983,6 +4155,7 @@
      */
     private boolean isSatellitePlmn(@NonNull String mccMnc) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            log("isSatellitePlmn: oemEnabledSatelliteFlag is disabled");
             return false;
         }
 
@@ -3993,11 +4166,19 @@
         } catch (Resources.NotFoundException ex) {
             loge("isSatellitePlmn: id= " + id + ", ex=" + ex);
         }
-        if (overlayMccMnc == null) {
-            return false;
-        } else {
-            return mccMnc.equals(overlayMccMnc);
+        if (TextUtils.isEmpty(overlayMccMnc) && isMockModemAllowed()) {
+            log("isSatellitePlmn: Read config_satellite_sim_identifier from device config");
+            overlayMccMnc = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY,
+                    "config_satellite_sim_identifier", "");
         }
+        log("isSatellitePlmn: overlayMccMnc=" + overlayMccMnc + ", mccMnc=" + mccMnc);
+        return TextUtils.equals(mccMnc, overlayMccMnc);
+    }
+
+    private boolean isMockModemAllowed() {
+        boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false);
+        return (SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)
+                || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false));
     }
 
     /**
@@ -4062,6 +4243,7 @@
             pw.println("activeDataSubId=" + getActiveDataSubscriptionId());
             pw.println("defaultSmsSubId=" + getDefaultSmsSubId());
             pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded());
+            pw.println("mUserIdToAvailableSubs=" + mUserIdToAvailableSubs);
             pw.println();
             for (int i = 0; i < mSimState.length; i++) {
                 pw.println("mSimState[" + i + "]="
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index a7382ef..0459bf6 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -597,8 +597,6 @@
                         log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
                                 + "getIccCardStatus");
                     }
-                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
-                            phoneId));
                     // slot status should be the same on all RILs; request it only for phoneId 0
                     if (phoneId == 0) {
                         if (DBG) {
@@ -608,6 +606,8 @@
                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
                                 phoneId));
                     }
+                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
+                            phoneId));
                     break;
                 case EVENT_GET_ICC_STATUS_DONE:
                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp
index 9fb4fe6..51ab617 100644
--- a/tests/telephonytests/Android.bp
+++ b/tests/telephonytests/Android.bp
@@ -41,6 +41,7 @@
         "truth",
         "testables",
         "platform-compat-test-rules",
+        "flag-junit",
     ],
 
     jarjar_rules: ":jarjar-rules-telephony-tests",
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
index 9fd89ff..e23a7f2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
@@ -41,12 +41,15 @@
 import android.testing.TestableLooper;
 import android.util.Pair;
 
+import com.android.internal.telephony.flags.FeatureFlags;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
 
 import java.security.PublicKey;
 import java.text.SimpleDateFormat;
@@ -87,7 +90,7 @@
                     + "\"public-key\": \"" + CERT + "\"}]}";
 
     private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
-
+    private FeatureFlags mFeatureFlags;
     @Before
     public void setUp() throws Exception {
         logd("CarrierActionAgentTest +Setup!");
@@ -98,7 +101,8 @@
         // Capture listener to emulate the carrier config change notification used later
         ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
-        mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone);
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
+        mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone, mFeatureFlags);
         verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
                 listenerArgumentCaptor.capture());
         mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 435763b..c613155 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -597,7 +597,7 @@
         doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory)
                 .makeWspTypeDecoder(nullable(byte[].class));
         doReturn(mImsCT).when(mTelephonyComponentFactory)
-                .makeImsPhoneCallTracker(nullable(ImsPhone.class));
+                .makeImsPhoneCallTracker(nullable(ImsPhone.class), any(FeatureFlags.class));
         doReturn(mCdmaSSM).when(mTelephonyComponentFactory)
                 .getCdmaSubscriptionSourceManagerInstance(nullable(Context.class),
                         nullable(CommandsInterface.class), nullable(Handler.class),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index a09994b..01a82ba 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -415,6 +415,47 @@
             .setPreferred(false)
             .build();
 
+    private final DataProfile mEsimBootstrapDataProfile = new DataProfile.Builder()
+            .setApnSetting(new ApnSetting.Builder()
+                    .setEntryName("ESIM BOOTSTRAP")
+                    .setApnName("ESIM BOOTSTRAP")
+                    .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+                    .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                            | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR)
+                    .setCarrierEnabled(true)
+                    .setEsimBootstrapProvisioning(true)
+                    .build())
+            .setPreferred(false)
+            .build();
+
+    private final DataProfile mEsimBootstrapImsProfile = new DataProfile.Builder()
+            .setApnSetting(new ApnSetting.Builder()
+                    .setEntryName("IMS BOOTSTRAP")
+                    .setApnName("IMS BOOTSTRAP")
+                    .setApnTypeBitmask(ApnSetting.TYPE_IMS)
+                    .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                            | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR)
+                    .setCarrierEnabled(true)
+                    .setEsimBootstrapProvisioning(true)
+                    .build())
+            .setPreferred(false)
+            .build();
+
+    private final DataProfile mEsimBootstrapRcsInfraStructureProfile =
+            new DataProfile.Builder()
+            .setApnSetting(new ApnSetting.Builder()
+                    .setEntryName("INFRASTRUCTURE BOOTSTRAP")
+                    .setApnName("INFRASTRUCTURE BOOTSTRAP")
+                    .setApnTypeBitmask(ApnSetting.TYPE_RCS)
+                    .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                            | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR)
+                    .setCarrierEnabled(true)
+                    .setInfrastructureBitmask(2)
+                    .setEsimBootstrapProvisioning(true)
+                    .build())
+            .setPreferred(false)
+            .build();
+
     /** Data call response map. The first key is the transport type, the second key is the cid. */
     private final Map<Integer, Map<Integer, DataCallResponse>> mDataCallResponses = new HashMap<>();
 
@@ -919,7 +960,8 @@
                 mGeneralPurposeDataProfileAlternative, mImsCellularDataProfile,
                 mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile,
                 mTetheringDataProfile, mMmsOnWlanDataProfile, mLowLatencyDataProfile,
-                mNtnDataProfile);
+                mNtnDataProfile, mEsimBootstrapDataProfile,
+                mEsimBootstrapImsProfile, mEsimBootstrapRcsInfraStructureProfile);
 
         doAnswer(invocation -> {
             DataProfile dp = (DataProfile) invocation.getArguments()[0];
@@ -951,7 +993,8 @@
                     (TelephonyNetworkRequest) invocation.getArguments()[0];
             int networkType = (int) invocation.getArguments()[1];
             boolean isNtn = (boolean) invocation.getArguments()[2];
-            boolean ignorePermanentFailure = (boolean) invocation.getArguments()[3];
+            boolean isEsimBootstrapProvisioning = (boolean) invocation.getArguments()[3];
+            boolean ignorePermanentFailure = (boolean) invocation.getArguments()[4];
 
             for (DataProfile dataProfile : profiles) {
                 ApnSetting apnSetting = dataProfile.getApnSetting();
@@ -960,20 +1003,24 @@
                         && (apnSetting.getNetworkTypeBitmask() == 0
                         || (apnSetting.getNetworkTypeBitmask()
                         & ServiceState.getBitmaskForTech(networkType)) != 0)
+                        && (isEsimBootstrapProvisioning
+                        == apnSetting.isEsimBootstrapProvisioning())
                         && ((isNtn && apnSetting.isForInfrastructure(
-                                ApnSetting.INFRASTRUCTURE_SATELLITE))
-                        || ((!isNtn && apnSetting.isForInfrastructure(
-                                ApnSetting.INFRASTRUCTURE_CELLULAR))))
+                        ApnSetting.INFRASTRUCTURE_SATELLITE))
+                        || (!isNtn && apnSetting.isForInfrastructure(
+                        ApnSetting.INFRASTRUCTURE_CELLULAR)))
                         && (ignorePermanentFailure || !apnSetting.getPermanentFailed())) {
                     return dataProfile;
                 }
             }
             logd("Cannot find data profile to satisfy " + networkRequest + ", network type="
                     + TelephonyManager.getNetworkTypeName(networkType) + ", ignorePermanentFailure="
-                    + ignorePermanentFailure + ", isNtn=" + isNtn);
+                    + ignorePermanentFailure + ", isNtn=" + isNtn + ","
+                    + "isEsimBootstrapProvisioning=" + isEsimBootstrapProvisioning);
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean(),
+                anyBoolean());
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(anyInt());
@@ -1181,6 +1228,18 @@
                 + dataNetworkList);
     }
 
+    private void verifyConnectedNetworkHasNoDataProfile(@NonNull DataProfile dataProfile)
+            throws Exception {
+        List<DataNetwork> dataNetworkList = getDataNetworks();
+        for (DataNetwork dataNetwork : getDataNetworks()) {
+            if (dataNetwork.isConnected() && dataNetwork.getDataProfile().equals(dataProfile)) {
+                fail("network with " + dataProfile + " is connected. dataNetworkList="
+                        + dataNetworkList);
+            }
+        }
+        return;
+    }
+
     private void verifyAllDataDisconnected() throws Exception {
         List<DataNetwork> dataNetworkList = getDataNetworks();
         assertWithMessage("All data should be disconnected but it's not. " + dataNetworkList)
@@ -1255,7 +1314,8 @@
                     + TelephonyManager.getNetworkTypeName(networkType));
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean(),
+                anyBoolean());
 
         // verify the network still connects
         verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any());
@@ -1300,7 +1360,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean(), anyBoolean());
+                        anyBoolean(), anyBoolean(), anyBoolean());
 
         NetworkCapabilities netCaps = new NetworkCapabilities();
         netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
@@ -1515,7 +1575,7 @@
         // Now RAT changes from UMTS to GSM
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM),
-                anyBoolean(), anyBoolean());
+                anyBoolean(), anyBoolean(), anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyAllDataDisconnected();
@@ -1529,14 +1589,14 @@
         // Now RAT changes from GSM to UMTS
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS),
-                anyBoolean(), anyBoolean());
+                anyBoolean(), anyBoolean(), anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean(), anyBoolean());
+                        anyBoolean(), anyBoolean(), anyBoolean());
         // Now RAT changes from UMTS to LTE
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
@@ -3531,7 +3591,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean(), anyBoolean());
+                        anyBoolean(), anyBoolean(), anyBoolean());
 
         NetworkCapabilities netCaps = new NetworkCapabilities();
         netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
@@ -4593,7 +4653,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean(), anyBoolean());
+                        anyBoolean(), anyBoolean(), anyBoolean());
         mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
@@ -4631,7 +4691,7 @@
                 createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mLowLatencyDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean(), anyBoolean());
+                        anyBoolean(), anyBoolean(), anyBoolean());
         processAllFutureMessages();
 
         dataNetworkList = getDataNetworks();
@@ -4664,7 +4724,7 @@
         // Mock the designated MMS profile when WLAN is preferred
         doReturn(mMmsOnWlanDataProfile).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_IWLAN),
-                anyBoolean(), anyBoolean());
+                anyBoolean(), anyBoolean(), anyBoolean());
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager,
                 createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE));
 
@@ -4686,4 +4746,132 @@
         processAllMessages();
         verifyConnectedNetworkHasDataProfile(mNtnDataProfile);
     }
+
+    @Test
+    public void testIsEsimBootStrapProvisioningActivatedWithFlagEnabledAndProvisioningClass() {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue();
+    }
+
+    @Test
+    public void testIsEsimBootStrapProvisioningActivatedWithFlagEnabledAndNoProvisioningClass() {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse();
+    }
+
+    @Test
+    public void testIsEsimBootStrapProvisioningActivatedWithFlagDisabledAndNoProvisioningClass() {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(false);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse();
+    }
+
+    @Test
+    public void testIsEsimBootStrapProvisioningActivatedWithFlagDisabledAndProvisioningClass() {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(false);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse();
+    }
+
+    @Test
+    public void testNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        processAllMessages();
+        verifyConnectedNetworkHasDataProfile(mEsimBootstrapDataProfile);
+
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS,
+                        NetworkCapabilities.NET_CAPABILITY_MMTEL));
+        setSuccessfulSetupDataResponse(mMockedDataServiceManagers
+                .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2);
+        processAllMessages();
+        verifyConnectedNetworkHasDataProfile(mEsimBootstrapImsProfile);
+
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS));
+        processAllMessages();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
+    }
+
+    @Test
+    public void testNetworkOnNonProvisioningProfileClass_WithFlagEnabled() throws Exception {
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        processAllMessages();
+        verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapDataProfile);
+
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS,
+                        NetworkCapabilities.NET_CAPABILITY_MMTEL));
+        setSuccessfulSetupDataResponse(mMockedDataServiceManagers
+                .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2);
+        processAllMessages();
+        verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapImsProfile);
+    }
+
+    @Test
+    public void testNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception {
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+        mIsNonTerrestrialNetwork = true;
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS));
+        processAllMessages();
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue();
+        verifyConnectedNetworkHasNoDataProfile(mNtnDataProfile);
+        verifyConnectedNetworkHasDataProfile(mEsimBootstrapRcsInfraStructureProfile);
+    }
+
+    @Test
+    public void testNonNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception {
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
+        doReturn(new SubscriptionInfoInternal.Builder().setId(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS));
+        processAllMessages();
+
+        assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue();
+        verifyConnectedNetworkHasNoDataProfile(mNtnDataProfile);
+        verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapRcsInfraStructureProfile);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
index f9a11be..f8d22cd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -84,8 +84,12 @@
     private static final String TETHERING_APN = "DUN_APN";
     private static final String APN_SET_ID_1_APN = "APN_SET_ID_1_APN";
     private static final String RCS_APN = "RCS_APN";
+    private static final String RCS_APN1 = "RCS_APN1";
     private static final String APN_SET_ID_1_TETHERING_APN = "APN_SET_ID_1_TETHERING_APN";
     private static final String MATCH_ALL_APN_SET_ID_IMS_APN = "MATCH_ALL_APN_SET_ID_IMS_APN";
+    private static final String ESIM_BOOTSTRAP_PROVISIONING_APN = "ESIM_BOOTSTRAP_PROVISIONING_APN";
+    private static final String TEST_BOOTSTRAP_APN =
+            "TEST_BOOTSTRAP_APN";
     private static final String PLMN = "330123";
     private static final int DEFAULT_APN_SET_ID = Telephony.Carriers.NO_APN_SET_ID;
     private static final int APN_SET_ID_1 = 1;
@@ -137,7 +141,8 @@
                 Telephony.Carriers.CARRIER_ID,
                 Telephony.Carriers.SKIP_464XLAT,
                 Telephony.Carriers.ALWAYS_ON,
-                Telephony.Carriers.INFRASTRUCTURE_BITMASK
+                Telephony.Carriers.INFRASTRUCTURE_BITMASK,
+                Telephony.Carriers.ESIM_BOOTSTRAP_PROVISIONING
         };
 
         private int mPreferredApnSet = 0;
@@ -177,7 +182,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                      // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 // default internet data profile for RAT CDMA, to test update preferred data profile
                 new Object[]{
@@ -213,7 +219,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         2,                      // id
@@ -248,7 +255,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         3,                      // id
@@ -283,7 +291,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         4,                      // id
@@ -319,7 +328,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 // This APN entry is created to test de-duping.
                 new Object[]{
@@ -356,7 +366,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         6,                      // id
@@ -392,7 +403,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         7,                      // id
@@ -428,7 +440,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         8,                      // id
@@ -464,7 +477,8 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        1                       // INFRASTRUCTURE_CELLULAR
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        0                       // esim_bootstrap_provisioning
                 },
                 new Object[]{
                         9,                      // id
@@ -500,7 +514,156 @@
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
                         0,                      // always_on
-                        2                       // INFRASTRUCTURE_SATELLITE
+                        2,                      // INFRASTRUCTURE_SATELLITE
+                        0                      // esim_bootstrap_provisioning
+                },
+                new Object[]{
+                        10,                      // id
+                        PLMN,                   // numeric
+                        ESIM_BOOTSTRAP_PROVISIONING_APN, // name
+                        ESIM_BOOTSTRAP_PROVISIONING_APN, // apn
+                        "",                     // proxy
+                        "",                     // port
+                        "",                     // mmsc
+                        "",                     // mmsproxy
+                        "",                     // mmsport
+                        "",                     // user
+                        "",                     // password
+                        -1,                     // authtype
+                        "default,supl",          // types
+                        "IPV4V6",               // protocol
+                        "IPV4V6",               // roaming_protocol
+                        1,                      // carrier_enabled
+                        0,                      // profile_id
+                        1,                      // modem_cognitive
+                        0,                      // max_conns
+                        0,                      // wait_time
+                        0,                      // max_conns_time
+                        0,                      // mtu
+                        1280,                   // mtu_v4
+                        1280,                   // mtu_v6
+                        "",                     // mvno_type
+                        "",                     // mnvo_match_data
+                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
+                        0,                      // lingering_network_type_bitmask
+                        MATCH_ALL_APN_SET_ID,   // apn_set_id
+                        -1,                     // carrier_id
+                        -1,                     // skip_464xlat
+                        0,                      // always_on
+                        1,                       // INFRASTRUCTURE_CELLULAR
+                        1                       // esim_bootstrap_provisioning
+                },
+                new Object[]{
+                        11,                      // id
+                        PLMN,                   // numeric
+                        IMS_APN,                // name
+                        IMS_APN,                // apn
+                        "",                     // proxy
+                        "",                     // port
+                        "",                     // mmsc
+                        "",                     // mmsproxy
+                        "",                     // mmsport
+                        "",                     // user
+                        "",                     // password
+                        -1,                     // authtype
+                        "ims",                  // types
+                        "IPV4V6",               // protocol
+                        "IPV4V6",               // roaming_protocol
+                        1,                      // carrier_enabled
+                        0,                      // profile_id
+                        1,                      // modem_cognitive
+                        0,                      // max_conns
+                        0,                      // wait_time
+                        0,                      // max_conns_time
+                        0,                      // mtu
+                        1280,                   // mtu_v4
+                        1280,                   // mtu_v6
+                        "",                     // mvno_type
+                        "",                     // mnvo_match_data
+                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
+                        0,                      // lingering_network_type_bitmask
+                        MATCH_ALL_APN_SET_ID,   // apn_set_id
+                        -1,                     // carrier_id
+                        -1,                     // skip_464xlat
+                        0,                      // always_on
+                        1,                       // INFRASTRUCTURE_SATELLITE
+                        1                       // esim_bootstrap_provisioning
+                },
+                new Object[]{
+                        12,                     // id
+                        PLMN,                   // numeric
+                        TEST_BOOTSTRAP_APN,     // name
+                        TEST_BOOTSTRAP_APN,      // apn
+                        "",                     // proxy
+                        "",                     // port
+                        "",                     // mmsc
+                        "",                     // mmsproxy
+                        "",                     // mmsport
+                        "",                     // user
+                        "",                     // password
+                        -1,                     // authtype
+                        "default",              // types
+                        "IPV4V6",               // protocol
+                        "IPV4V6",               // roaming_protocol
+                        1,                      // carrier_enabled
+                        0,                      // profile_id
+                        1,                      // modem_cognitive
+                        0,                      // max_conns
+                        0,                      // wait_time
+                        0,                      // max_conns_time
+                        0,                      // mtu
+                        1280,                   // mtu_v4
+                        1280,                   // mtu_v6
+                        "",                     // mvno_type
+                        "",                     // mnvo_match_data
+                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
+                        0,                      // lingering_network_type_bitmask
+                        MATCH_ALL_APN_SET_ID,   // apn_set_id
+                        -1,                     // carrier_id
+                        -1,                     // skip_464xlat
+                        0,                      // always_on
+                        2,                       // INFRASTRUCTURE_SATELLITE
+                        1                       // esim_bootstrap_provisioning
+                },
+                new Object[]{
+                        13,                      // id
+                        PLMN,                   // numeric
+                        RCS_APN1,                // name
+                        RCS_APN1,                // apn
+                        "",                     // proxy
+                        "",                     // port
+                        "",                     // mmsc
+                        "",                     // mmsproxy
+                        "",                     // mmsport
+                        "",                     // user
+                        "",                     // password
+                        -1,                     // authtype
+                        "rcs",                  // types
+                        "IPV4V6",               // protocol
+                        "IPV4V6",               // roaming_protocol
+                        1,                      // carrier_enabled
+                        0,                      // profile_id
+                        1,                      // modem_cognitive
+                        0,                      // max_conns
+                        0,                      // wait_time
+                        0,                      // max_conns_time
+                        0,                      // mtu
+                        1280,                   // mtu_v4
+                        1280,                   // mtu_v6
+                        "",                     // mvno_type
+                        "",                     // mnvo_match_data
+                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
+                        0,                      // lingering_network_type_bitmask
+                        DEFAULT_APN_SET_ID,     // apn_set_id
+                        -1,                     // carrier_id
+                        -1,                     // skip_464xlat
+                        0,                      // always_on
+                        2,                       // INFRASTRUCTURE_SATELLITE
+                        1                       // esim_bootstrap_provisioning
                 }
         );
 
@@ -716,7 +879,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -727,7 +890,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -737,7 +900,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(IMS_APN);
 
@@ -746,7 +909,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dp).isNull();
 
         doReturn(new NetworkRegistrationInfo.Builder()
@@ -759,7 +922,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_NR, false, false);
+                TelephonyManager.NETWORK_TYPE_NR, false, false , false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(TETHERING_APN);
     }
@@ -771,7 +934,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_GSM, false, false);
+                TelephonyManager.NETWORK_TYPE_GSM, false, false, false);
         // Should not find data profile due to RAT incompatible.
         assertThat(dp).isNull();
     }
@@ -783,14 +946,14 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         logd("Set setLastSetupTimestamp on " + dataProfile);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
 
         // See if another one can be returned.
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
     }
 
@@ -801,7 +964,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -814,7 +977,7 @@
                 .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
                 0, NetworkRequest.Type.REQUEST), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -830,7 +993,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -846,7 +1009,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -864,7 +1027,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, true, false);
+                TelephonyManager.NETWORK_TYPE_LTE, true, false, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(RCS_APN);
@@ -877,7 +1040,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         dataProfile.setPreferred(true);
@@ -891,14 +1054,14 @@
 
         // Test See if the same one can be returned.
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
 
         // Test Another default internet network connected due to RAT changed. Verify the preferred
         // data profile is updated.
         DataProfile legacyRatDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_CDMA, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_CDMA, false, false, false);
         DataNetwork legacyRatInternetNetwork = Mockito.mock(DataNetwork.class);
         doReturn(legacyRatDataProfile).when(legacyRatInternetNetwork).getDataProfile();
         doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr)))
@@ -917,7 +1080,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                         .build(), mPhone);
         DataProfile dunDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         DataNetwork dunInternetNetwork = Mockito.mock(DataNetwork.class);
         doReturn(dunDataProfile).when(dunInternetNetwork).getDataProfile();
         doReturn(new DataNetworkController.NetworkRequestList(List.of(dunTnr)))
@@ -1016,7 +1179,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isNull();
 
         // expect default EIMS when SIM absent
@@ -1025,7 +1188,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
 
         // expect no default IMS when SIM absent
@@ -1034,7 +1197,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isEqualTo(null);
 
         // Verify null as initial attached data profile is sent to modem
@@ -1064,7 +1227,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isNull();
 
         // expect default EIMS when SIM absent
@@ -1073,7 +1236,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
 
         // expect no default IMS when SIM absent
@@ -1082,7 +1245,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isEqualTo(null);
 
         // Verify in legacy mode, null IA should NOT be sent to modem
@@ -1117,7 +1280,7 @@
                 new TelephonyNetworkRequest(new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone),
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN);
     }
 
@@ -1129,7 +1292,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         // This should get the merged data profile after deduping.
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
     }
 
@@ -1266,7 +1429,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                 .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         assertThat(dataProfile.getApn()).isEqualTo("sos");
         assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos");
@@ -1283,7 +1446,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         DataNetwork internetNetwork = Mockito.mock(DataNetwork.class);
@@ -1354,7 +1517,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
@@ -1367,7 +1530,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
     }
@@ -1648,7 +1811,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         // Mark the APN as permanent failed.
         dp.getApnSetting().setPermanentFailed(true);
@@ -1656,7 +1819,8 @@
         // Data profile manager should return a different data profile for setup as the previous
         // data profile has been marked as permanent failed.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNotEqualTo(dp);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false))
+                .isNotEqualTo(dp);
     }
 
     @Test
@@ -1671,7 +1835,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
         // Mark the APN as permanent failed.
         dp.getApnSetting().setPermanentFailed(true);
@@ -1679,7 +1843,8 @@
         // Since preferred APN is already set, and that data profile was marked as permanent failed,
         // so this should result in getting nothing.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNull();
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false))
+                .isNull();
     }
 
     private void changeSimStateTo(@TelephonyManager.SimState int simState) {
@@ -1700,6 +1865,98 @@
         // Verify the we can get the previously permanent failed data profile again.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 new TelephonyNetworkRequest(request, mPhone),
-                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNotNull();
+                TelephonyManager.NETWORK_TYPE_LTE, false, false, false))
+                .isNotNull();
     }
+
+    @Test
+    public void testDifferentNetworkRequestProfilesOnEsimBootStrapProvisioning() {
+        Mockito.clearInvocations(mDataProfileManagerCallback);
+        Mockito.clearInvocations(mMockedWwanDataServiceManager);
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+
+        // SIM inserted
+        mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget();
+        processAllMessages();
+
+        // expect default profile for internet network request, when esim bootstrap provisioning
+        // flag is enabled at data profile, during esim bootstrap provisioning
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build(), mPhone);
+        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
+        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(
+                "ESIM_BOOTSTRAP_PROVISIONING_APN");
+
+        // expect IMS profile for ims network request, when esim bootstrap provisioning flag
+        // is enabled at data profile, during esim bootstrap provisioning
+        tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+                 .build(), mPhone);
+        dataProfile  = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
+        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("IMS_APN");
+
+        // expect no mms profile for mms network request, when esim bootstrap provisioning flag
+        // is disabled at data profile, during esim bootstrap provisioning
+        tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
+                .build(), mPhone);
+        dataProfile  = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
+        assertThat(dataProfile).isEqualTo(null);
+
+        // expect no rcs profile for rcs network request, when esim bootstrap provisioning flag
+        // is disabled at data profile, during esim bootstrap provisioning
+        tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                .build(), mPhone);
+        dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
+        assertThat(dataProfile).isEqualTo(null);
+    }
+
+    @Test
+    public void testEsimBootstrapProvisioningEnabled_MultipleProfile() {
+        Mockito.clearInvocations(mDataProfileManagerCallback);
+        Mockito.clearInvocations(mMockedWwanDataServiceManager);
+
+        // SIM inserted
+        mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget();
+        processAllMessages();
+
+        // expect initial default profile entry selected for internet network request, when
+        // multiple esim bootstrap provisioning flag is enabled at data profile for same apn
+        // type
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build(), mPhone);
+        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
+        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(
+                ESIM_BOOTSTRAP_PROVISIONING_APN);
+    }
+
+    @Test
+    public void testInfrastructureProfileOnEsimBootStrapProvisioning() {
+        Mockito.clearInvocations(mDataProfileManagerCallback);
+        Mockito.clearInvocations(mMockedWwanDataServiceManager);
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+
+        // SIM inserted
+        mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget();
+        processAllMessages();
+
+        // expect initial default profile entry selected for internet network request, when
+        // multiple esim bootstrap provisioning flag is enabled at data profile for same apn
+        // type
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                .build(), mPhone);
+        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, true, true, false);
+        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(RCS_APN1);
+    }
+
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
index a2a55ee..1734244 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
@@ -20,6 +20,8 @@
 import static android.telephony.DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.eq;
@@ -31,11 +33,14 @@
 import android.os.AsyncResult;
 import android.os.CancellationSignal;
 import android.os.Handler;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelector;
 import android.telephony.EmergencyRegResult;
 import android.telephony.TransportSelectorCallback;
 import android.telephony.WwanSelectorCallback;
+import android.telephony.data.ApnSetting;
 import android.telephony.ims.ImsReasonInfo;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -43,6 +48,7 @@
 
 import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 
 import org.junit.After;
 import org.junit.Before;
@@ -290,6 +296,31 @@
         verify(domainSelector).finishSelection();
     }
 
+    @Test
+    @SmallTest
+    public void testQualifiedNetworkTypesChanged() throws Exception {
+        mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true,
+                mDomainSelectionController);
+
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+
+        assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList))
+                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.IWLAN }));
+
+        assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList))
+                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+        networksList.clear();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.EUTRAN }));
+
+        assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList))
+                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+    }
+
     private DomainSelectionService.SelectionAttributes getSelectionAttributes(
             int slotId, int subId, int selectorType, boolean isEmergency,
             boolean exited, int callFailCause, String callId, String number,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java
index 0c64b82..d0b2fce 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java
@@ -17,7 +17,6 @@
 
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN;
-import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
 import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
@@ -38,25 +37,34 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.DomainSelectionService;
 import android.telephony.EmergencyRegResult;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.TransportSelectorCallback;
 import android.telephony.WwanSelectorCallback;
+import android.telephony.data.ApnSetting;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.data.AccessNetworksManager;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 @RunWith(AndroidTestingRunner.class)
@@ -96,7 +104,7 @@
     @Test
     @SmallTest
     public void testSelectDomainWifi() throws Exception {
-        doReturn(TRANSPORT_TYPE_WLAN).when(mAnm).getPreferredTransport(anyInt());
+        doReturn(TRANSPORT_TYPE_WWAN).when(mAnm).getPreferredTransport(anyInt());
         replaceInstance(EmergencyCallDomainSelectionConnection.class,
                 "mEmergencyStateTracker", mEcDsc, mEmergencyStateTracker);
 
@@ -120,6 +128,21 @@
 
         mTransportCallback.onWlanSelected(true);
 
+        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        ArgumentCaptor<Integer> msgCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mAnm).registerForQualifiedNetworksChanged(
+                handlerCaptor.capture(), msgCaptor.capture());
+
+        assertFalse(future.isDone());
+
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.IWLAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
+        Handler handler = handlerCaptor.getValue();
+        Integer msg = msgCaptor.getValue();
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
+
         assertTrue(future.isDone());
         assertEquals((long) DOMAIN_NON_3GPP_PS, (long) future.get());
         verify(mEmergencyStateTracker).onEmergencyTransportChanged(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java
index 25ccecb..3b6d0c3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java
@@ -29,19 +29,23 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelector;
 import android.telephony.NetworkRegistrationInfo;
+import android.telephony.data.ApnSetting;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.data.AccessNetworksManager;
+import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks;
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 
 import org.junit.After;
@@ -51,6 +55,8 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -151,9 +157,13 @@
         verify(mPhone).notifyEmergencyDomainSelected(
                 eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN));
 
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.IWLAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
         Handler handler = handlerCaptor.getValue();
         Integer msg = msgCaptor.getValue();
-        handler.handleMessage(Message.obtain(handler, msg.intValue()));
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
         processAllMessages();
 
         assertTrue(future.isDone());
@@ -214,9 +224,13 @@
         verify(mPhone).notifyEmergencyDomainSelected(
                 eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN));
 
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.IWLAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
         Handler handler = handlerCaptor.getValue();
         Integer msg = msgCaptor.getValue();
-        handler.handleMessage(Message.obtain(handler, msg.intValue()));
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
         processAllMessages();
 
         assertTrue(future.isDone());
@@ -273,9 +287,13 @@
         verify(mPhone).notifyEmergencyDomainSelected(
                 eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN));
 
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.EUTRAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
         Handler handler = handlerCaptor.getValue();
         Integer msg = msgCaptor.getValue();
-        handler.handleMessage(Message.obtain(handler, msg.intValue()));
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
         processAllMessages();
 
         assertTrue(future.isDone());
@@ -364,9 +382,13 @@
         verify(mPhone).notifyEmergencyDomainSelected(
                 eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN));
 
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.EUTRAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
         Handler handler = handlerCaptor.getValue();
         Integer msg = msgCaptor.getValue();
-        handler.handleMessage(Message.obtain(handler, msg.intValue()));
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
         processAllMessages();
 
         assertTrue(future.isDone());
@@ -445,9 +467,13 @@
         verify(mPhone).notifyEmergencyDomainSelected(
                 eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN));
 
+        List<QualifiedNetworks> networksList = new ArrayList<>();
+        networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY,
+                new int[]{ AccessNetworkType.EUTRAN }));
+        AsyncResult ar = new AsyncResult(null, networksList, null);
         Handler handler = handlerCaptor.getValue();
         Integer msg = msgCaptor.getValue();
-        handler.handleMessage(Message.obtain(handler, msg.intValue()));
+        handler.handleMessage(Message.obtain(handler, msg.intValue(), ar));
         processAllMessages();
         mDsConnection.finishSelection();
 
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 0be1927..7da79a6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -830,6 +830,34 @@
 
     @Test
     @SmallTest
+    public void testRecoverNormalInCellularWhenVoWiFiConnected() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        // Create test Phones
+        Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        // Call startEmergencyCall() to set testPhone
+        CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone,
+                TEST_CALL_ID, false);
+
+        // Set emergency transport
+        emergencyStateTracker.onEmergencyTransportChanged(
+                EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WLAN);
+
+        // Set call properties
+        emergencyStateTracker.onEmergencyCallPropertiesChanged(
+                android.telecom.Connection.PROPERTY_WIFI, TEST_CALL_ID);
+
+        verify(testPhone, times(0)).cancelEmergencyNetworkScan(anyBoolean(), any());
+
+        // Set call to ACTIVE
+        emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID);
+
+        verify(testPhone, times(1)).cancelEmergencyNetworkScan(eq(true), any());
+    }
+
+    @Test
+    @SmallTest
     public void testStartEmergencySms() {
         EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
                 /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index d0a2094..04ae9d0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -94,6 +94,7 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.RtpHeaderExtensionType;
 import android.telephony.ims.SrvccCall;
 import android.telephony.ims.aidl.IImsTrafficSessionCallback;
@@ -160,6 +161,7 @@
     private Bundle mBundle = new Bundle();
     private static final int SUB_0 = 0;
     @Nullable private VtDataUsageProvider mVtDataUsageProvider;
+    private ProvisioningManager.Callback mConfigCallback;
 
     // Mocked classes
     private ArgumentCaptor<Set<RtpHeaderExtensionType>> mRtpHeaderExtensionTypeCaptor;
@@ -282,10 +284,14 @@
         DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver);
         doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported();
 
+        doReturn(false)
+                .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges();
+
         // Capture CarrierConfigChangeListener to emulate the carrier config change notification
         ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
-        mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run);
+        mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run,
+                mFeatureFlags);
         verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
                 listenerArgumentCaptor.capture());
         mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
@@ -309,6 +315,12 @@
 
         verify(mMockConnector).connect();
         mConnectorListener.connectionReady(mImsManager, SUB_0);
+
+        final ArgumentCaptor<ProvisioningManager.Callback> configCallbackCaptor =
+                ArgumentCaptor.forClass(ProvisioningManager.Callback.class);
+        verify(mImsConfig).addConfigCallback(configCallbackCaptor.capture());
+        mConfigCallback = configCallbackCaptor.getValue();
+        assertNotNull(mConfigCallback);
     }
 
     @After
@@ -2641,6 +2653,73 @@
                 eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any());
     }
 
+    @Test
+    public void testProvisioningItemAndUpdateImsServiceConfigWithFeatureEnabled() {
+        doReturn(true)
+                .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges();
+
+        // Receive a subscription loaded and IMS connection ready indication.
+        mContextFixture.getCarrierConfigBundle().putBoolean(
+                CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+        sendCarrierConfigChanged();
+        processAllMessages();
+        verify(mImsManager, times(1)).updateImsServiceConfig();
+
+        logd("deliver provisioning items");
+        mConfigCallback.onProvisioningIntChanged(27, 2);
+        mConfigCallback.onProvisioningIntChanged(28, 1);
+        mConfigCallback.onProvisioningIntChanged(10, 1);
+        mConfigCallback.onProvisioningIntChanged(11, 1);
+        mConfigCallback.onProvisioningStringChanged(12, "msg.pc.t-mobile.com");
+        mConfigCallback.onProvisioningIntChanged(26, 0);
+        mConfigCallback.onProvisioningIntChanged(66, 0);
+
+        logd("proc provisioning items");
+        processAllFutureMessages();
+
+        // updateImsServiceConfig is called with below 2 events.
+        // 1. CarrierConfig
+        // 2. ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28), ProvisioningManager
+        // .KEY_VOLTE_PROVISIONING_STATUS(10) and ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11)
+        verify(mImsManager, times(2)).updateImsServiceConfig();
+    }
+
+
+    @Test
+    public void testProvisioningItemAndUpdateImsServiceConfigWithFeatureDisabled() {
+        doReturn(false)
+                .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges();
+
+        // Receive a subscription loaded and IMS connection ready indication.
+        mContextFixture.getCarrierConfigBundle().putBoolean(
+                CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+        sendCarrierConfigChanged();
+        processAllMessages();
+        verify(mImsManager, times(1)).updateImsServiceConfig();
+
+        logd("deliver provisioning items");
+        mConfigCallback.onProvisioningIntChanged(27, 2);
+        //ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28) call updateImsServiceConfig.
+        mConfigCallback.onProvisioningIntChanged(28, 1);
+        //ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS(10) call updateImsServiceConfig.
+        mConfigCallback.onProvisioningIntChanged(10, 1);
+        //ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11) call updateImsServiceConfig.
+        mConfigCallback.onProvisioningIntChanged(11, 1);
+        mConfigCallback.onProvisioningStringChanged(12, "msg.pc.t-mobile.com");
+        mConfigCallback.onProvisioningIntChanged(26, 0);
+        mConfigCallback.onProvisioningIntChanged(66, 0);
+
+        logd("proc provisioning items");
+        processAllFutureMessages();
+
+        // updateImsServiceConfig is called with below 4 events.
+        // 1. CarrierConfig
+        // 2. ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28)
+        // 3. ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS(10)
+        // 4. ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11)
+        verify(mImsManager, times(4)).updateImsServiceConfig();
+    }
+
     private void sendCarrierConfigChanged() {
         mCarrierConfigChangeListener.onCarrierConfigChanged(mPhone.getPhoneId(), mPhone.getSubId(),
                 TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index 95f47c5..4e61c67 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -1118,6 +1118,9 @@
     @Test
     @SmallTest
     public void testClearPhoneNumberForSourceIms() {
+        doReturn(true).when(mFeatureFlags)
+                .clearCachedImsPhoneNumberWhenDeviceLostImsRegistration();
+
         // In reality the method under test runs in phone process so has MODIFY_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(MODIFY_PHONE_STATE);
         int subId = 1;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index 05489dc..e4e2434 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -105,7 +105,9 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.euicc.EuiccController;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback;
 import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider;
+import com.android.internal.telephony.subscription.SubscriptionManagerService.BinderWrapper;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap;
 import com.android.internal.telephony.uicc.IccCardStatus;
@@ -155,6 +157,7 @@
     private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback;
     private EuiccController mEuiccController;
     private FeatureFlags mFlags;
+    private BinderWrapper mBinder;
     private Set<Integer> mActiveSubs = new ArraySet<>();
 
     @Rule
@@ -195,6 +198,10 @@
         doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1));
         doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2));
 
+        mBinder = Mockito.mock(BinderWrapper.class);
+        doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+        replaceInstance(SubscriptionManagerService.class, "BINDER_WRAPPER", null, mBinder);
+
         doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
 
         ((MockContentResolver) mContext.getContentResolver()).addProvider(
@@ -256,6 +263,12 @@
         return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT);
     }
 
+    private SubscriptionDatabaseManagerCallback getSubscriptionDatabaseCallback() throws Exception {
+        Field field = SubscriptionDatabaseManager.class.getDeclaredField("mCallback");
+        field.setAccessible(true);
+        return (SubscriptionDatabaseManagerCallback) field.get(getSubscriptionDatabaseManager());
+    }
+
     /**
      * Insert the subscription info to the database. This is an instant insertion method. For real
      * insertion sequence please use {@link #testInsertNewSim()}.
@@ -265,7 +278,6 @@
      */
     private int insertSubscription(@NonNull SubscriptionInfoInternal subInfo) {
         try {
-            mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
             subInfo = new SubscriptionInfoInternal.Builder(subInfo)
                     .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build();
             int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo);
@@ -277,17 +289,12 @@
             field.setAccessible(true);
             SubscriptionMap<Integer, Integer> map = (SubscriptionMap<Integer, Integer>)
                     field.get(mSubscriptionManagerServiceUT);
-            Class[] cArgs = new Class[2];
-            cArgs[0] = Object.class;
-            cArgs[1] = Object.class;
 
             if (subInfo.getSimSlotIndex() >= 0) {
                 // Change the slot -> subId mapping
                 map.put(subInfo.getSimSlotIndex(), subId);
             }
 
-            mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
-            processAllMessages();
             verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId));
             Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback);
 
@@ -964,7 +971,7 @@
     }
 
     @Test
-    public void testSetIconTint() throws Exception {
+    public void testSetIconTint() {
         insertSubscription(FAKE_SUBSCRIPTION_INFO1);
 
         // Should fail without MODIFY_PHONE_STATE
@@ -1150,6 +1157,299 @@
     }
 
     @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testIsSubscriptionAssociatedWithUserMultiSubs() {
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), 1);
+
+        // Verify sub 1 unassociated is visible to all profiles
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+
+        // Assign sub 2 to work profile
+        insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, 2);
+        processAllMessages();
+        // Verify work profile can only see its dedicated sub 2
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false);
+        // Verify personal profile can only see the unassigned sub 1
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_USER_HANDLE)).isEqualTo(false);
+
+        // Sub 2 is deactivated, but still on device, verify visibility doesn't change.
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.updateSimState(
+                1, TelephonyManager.SIM_STATE_NOT_READY, null, null);
+        processAllMessages();
+        // Verify work profile can only see its dedicated sub 2
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false);
+        // Verify personal profile can only see the unassigned sub 1
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_USER_HANDLE)).isEqualTo(false);
+
+        // Sub 2 is removed from the device.
+        mSubscriptionManagerServiceUT.updateSimState(
+                1, TelephonyManager.SIM_STATE_ABSENT, null, null);
+        processAllMessages();
+        // Verify the visibility of the unassigned sub 1 is restored to both profiles.
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+    }
+
+    @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testSubscriptionAssociationWorkProfileCallerVisibility() {
+        // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to
+        // the unassociated sub.
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        // Sub 1 is associated with work profile; Sub 2 is unassociated.
+        int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, subId1);
+        int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), subId2);
+        // Set Sub 1 default data sub
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1);
+        processAllMessages();
+
+        // Calling from work profile
+        doReturn(FAKE_MANAGED_PROFILE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+
+        // Test getAccessibleSubscriptionInfoList
+        doReturn(true).when(mEuiccManager).isEnabled();
+        doReturn(true).when(mSubscriptionManager).canManageSubscription(
+                any(SubscriptionInfo.class), eq(CALLING_PACKAGE));
+        assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList(
+                CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()));
+        // Test getActiveSubIdList, System
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/))
+                .isEqualTo(new int[]{subId1, subId2});
+        // Test get getActiveSubInfoCount
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
+                CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+        // Test getActiveSubscriptionInfo
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForIccId
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForSimSlotIndex
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
+                CALLING_PACKAGE, CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getAllSubInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test getAvailableSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getDefaultDataSubId
+        assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1);
+        // Test getDefault<Sms/Voice>SubIdAsUser
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        // Test getEnabledSubscriptionId
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(
+                subId1);
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo(
+                subId2);
+        // Test getOpportunisticSubscriptions
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE);
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE);
+        processAllMessages();
+        assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getSubscriptionInfo - can get both as it's an internal getter
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getSubscriptionInfoListAssociatedWithUser
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getSubscriptionsInGroup
+        setCarrierPrivilegesForSubId(true, subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup(
+                ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)
+                .stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test isActiveSubId
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        // Test isSubscriptionEnabled
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue();
+    }
+
+    @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testSubscriptionAssociationPersonalCallerVisibility() {
+        // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to
+        // the unassociated sub.
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        // Sub 1 is unassociated; Sub 2 is associated with work profile.
+        int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), subId1);
+        int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, subId2);
+        // Set Sub 1 default data sub
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1);
+        processAllMessages();
+
+        // Calling from a profile that owns no dedicated subs.
+        doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+
+        // Test getAccessibleSubscriptionInfoList
+        doReturn(true).when(mEuiccManager).isEnabled();
+        doReturn(true).when(mSubscriptionManager).canManageSubscription(
+                any(SubscriptionInfo.class), eq(CALLING_PACKAGE));
+        assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList(
+                CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()));
+        // Test getActiveSubIdList, System
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/))
+                .isEqualTo(new int[]{subId1, subId2});
+        // Test get getActiveSubInfoCount
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
+                CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+        // Test getActiveSubscriptionInfo
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForIccId
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForSimSlotIndex
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
+                        CALLING_PACKAGE, CALLING_FEATURE).stream()
+                .map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getAllSubInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test getAvailableSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getDefaultDataSubId
+        assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1);
+        // Test getDefault<Sms/Voice>SubIdAsUser
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        // Test getEnabledSubscriptionId
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(
+                subId1);
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo(
+                subId2);
+        // Test getOpportunisticSubscriptions
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE);
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE);
+        processAllMessages();
+        assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getSubscriptionInfo - can get both as it's an internal getter
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getSubscriptionInfoListAssociatedWithUser
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser(
+                        FAKE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getSubscriptionsInGroup
+        setCarrierPrivilegesForSubId(true, subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup(
+                        ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)
+                .stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test isActiveSubId
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        // Test isSubscriptionEnabled
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue();
+    }
+
+    @Test
     public void testSetUsageSetting() {
         insertSubscription(FAKE_SUBSCRIPTION_INFO1);