Merge "Add LTE_CA to auto data switch table" 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/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index 4ec1f71..3f3d297 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -118,6 +118,7 @@
     protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList();
     protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList();
     protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList();
+    protected RegistrantList mImeiInfoRegistrants = new RegistrantList();
 
     @UnsupportedAppUsage
     protected Registrant mGsmSmsRegistrant;
@@ -1174,4 +1175,12 @@
     public void unregisterForTriggerImsDeregistration(Handler h) {
         mTriggerImsDeregistrationRegistrants.remove(h);
     }
+
+    /**
+     * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+     */
+    @Override
+    public void registerForImeiMappingChanged(Handler h, int what, Object obj) {
+        mImeiInfoRegistrants.add(h, what, obj);
+    }
 }
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/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 71c2001..1ed6be0 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1735,6 +1735,12 @@
     public void getImei(Message response);
 
     /**
+     * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+     */
+
+    public void registerForImeiMappingChanged(Handler h, int what, Object obj);
+
+    /**
      * Request the device MDN / H_SID / H_NID / MIN.
      * "response" is const char **
      *   [0] is MDN if CDMA subscription is available
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 6f30fb5..b5cc37b 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -511,9 +511,10 @@
         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);
         initializeCarrierApps();
     }
 
@@ -3170,19 +3171,7 @@
             }
             break;
             case EVENT_GET_DEVICE_IMEI_DONE :
-                ar = (AsyncResult)msg.obj;
-                if (ar.exception != null || ar.result == null) {
-                    loge("Exception received : " + ar.exception);
-                    break;
-                }
-                ImeiInfo imeiInfo = (ImeiInfo) ar.result;
-                if (!TextUtils.isEmpty(imeiInfo.imei)) {
-                    mImeiType = imeiInfo.type;
-                    mImei = imeiInfo.imei;
-                    mImeiSv = imeiInfo.svn;
-                } else {
-                    // TODO Report telephony anomaly
-                }
+                parseImeiInfo(msg);
                 break;
             case EVENT_GET_DEVICE_IDENTITY_DONE:{
                 ar = (AsyncResult)msg.obj;
@@ -3668,11 +3657,33 @@
                     rsp.sendToTarget();
                 }
                 break;
+
+            case EVENT_IMEI_MAPPING_CHANGED:
+                logd("EVENT_GET_DEVICE_IMEI_CHANGE_DONE phoneId = " + getPhoneId());
+                parseImeiInfo(msg);
+                break;
+
             default:
                 super.handleMessage(msg);
         }
     }
 
+    private void parseImeiInfo(Message msg) {
+        AsyncResult ar = (AsyncResult)msg.obj;
+        if (ar.exception != null || ar.result == null) {
+            loge("parseImeiInfo :: Exception received : " + ar.exception);
+            return;
+        }
+        ImeiInfo imeiInfo = (ImeiInfo) ar.result;
+        if (!TextUtils.isEmpty(imeiInfo.imei)) {
+            mImeiType = imeiInfo.type;
+            mImei = imeiInfo.imei;
+            mImeiSv = imeiInfo.svn;
+        } else {
+            loge("parseImeiInfo :: IMEI value is empty");
+        }
+    }
+
     /**
      * Check if a different SIM is inserted at this slot from the last time. Storing last subId
      * in SharedPreference for now to detect SIM change.
diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java
index 0ee40bb..3893c6a 100644
--- a/src/java/com/android/internal/telephony/ModemIndication.java
+++ b/src/java/com/android/internal/telephony/ModemIndication.java
@@ -19,12 +19,14 @@
 import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM;
 
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED;
 
 import android.hardware.radio.modem.IRadioModemIndication;
+import android.hardware.radio.modem.ImeiInfo;
 import android.os.AsyncResult;
 
 import java.util.ArrayList;
@@ -132,4 +134,18 @@
     public int getInterfaceVersion() {
         return IRadioModemIndication.VERSION;
     }
+
+    /**
+     * Indicates when there is a change in the IMEI with respect to the sim slot.
+     *
+     * @param imeiInfo IMEI information
+     */
+    public void onImeiMappingChanged(int indicationType, ImeiInfo imeiInfo) {
+        mRil.processIndication(HAL_SERVICE_MODEM, indicationType);
+
+        if (mRil.isLogOrTrace()) {
+            mRil.unsljLogMore(RIL_UNSOL_IMEI_MAPPING_CHANGED, "ImeiMappingChanged");
+        }
+        mRil.notifyRegistrantsImeiMappingChanged(imeiInfo);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 50cf844..72d0622 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -253,8 +253,8 @@
     protected static final int EVENT_TRIGGER_NOTIFY_ANBR = 68;
     protected static final int EVENT_GET_N1_MODE_ENABLED_DONE = 69;
     protected static final int EVENT_SET_N1_MODE_ENABLED_DONE = 70;
-
-    protected static final int EVENT_LAST = EVENT_SET_N1_MODE_ENABLED_DONE;
+    protected static final int EVENT_IMEI_MAPPING_CHANGED = 71;
+    protected static final int EVENT_LAST = EVENT_IMEI_MAPPING_CHANGED;
 
     // For shared prefs.
     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 7e8bfe8..da15df6 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -36,6 +36,7 @@
 import android.hardware.radio.V1_0.RadioIndicationType;
 import android.hardware.radio.V1_0.RadioResponseInfo;
 import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.modem.ImeiInfo;
 import android.net.KeepalivePacketData;
 import android.net.LinkProperties;
 import android.os.AsyncResult;
@@ -5785,6 +5786,13 @@
         }
     }
 
+    void notifyRegistrantsImeiMappingChanged(ImeiInfo imeiInfo) {
+        if (mImeiInfoRegistrants != null) {
+            mImeiInfoRegistrants.notifyRegistrants(
+                    new AsyncResult(null, imeiInfo, null));
+        }
+    }
+
     @UnsupportedAppUsage
     void riljLog(String msg) {
         Rlog.d(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]"));
diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java
index c2c29f8..cb5684f 100644
--- a/src/java/com/android/internal/telephony/RILUtils.java
+++ b/src/java/com/android/internal/telephony/RILUtils.java
@@ -241,6 +241,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ICC_SLOT_STATUS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_STATUS;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
@@ -5269,6 +5270,8 @@
                 return "UNSOL_NOTIFY_ANBR";
             case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION:
                 return "UNSOL_TRIGGER_IMS_DEREGISTRATION";
+            case RIL_UNSOL_IMEI_MAPPING_CHANGED:
+                return "UNSOL_IMEI_MAPPING_CHANGED";
             default:
                 return "<unknown response " + response + ">";
         }
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 68bac97..8146983 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -45,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;
@@ -97,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;
@@ -132,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;
@@ -1175,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.
@@ -1490,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(
@@ -4145,6 +4155,7 @@
      */
     private boolean isSatellitePlmn(@NonNull String mccMnc) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            log("isSatellitePlmn: oemEnabledSatelliteFlag is disabled");
             return false;
         }
 
@@ -4155,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));
     }
 
     /**
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/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 5aa474e..2563fdf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -2734,4 +2734,31 @@
         verify(mSimulatedCommandsVerifier).getNetworkSelectionMode(any(Message.class));
         verify(mSimulatedCommandsVerifier).setNetworkSelectionModeAutomatic(any(Message.class));
     }
+
+    /**
+     * Verify the ImeiMappingChange and EVENT_GET_DEVICE_IMEI_CHANGE_DONE are handled properly.
+     */
+    @Test
+    public void testChangeInPrimaryImei() {
+        // Initially assign the primaryImei and test it.
+        Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE);
+        ImeiInfo imeiInfo = new ImeiInfo();
+        imeiInfo.imei = FAKE_IMEI;
+        imeiInfo.svn = FAKE_IMEISV;
+        imeiInfo.type = ImeiInfo.ImeiType.PRIMARY;
+        AsyncResult.forMessage(message, imeiInfo, null);
+        mPhoneUT.handleMessage(message);
+        assertEquals(Phone.IMEI_TYPE_PRIMARY, mPhoneUT.getImeiType());
+        assertEquals(FAKE_IMEI, mPhoneUT.getImei());
+
+        // Now update the same one to secondary and check whether it is reflecting or not.
+        message = mPhoneUT.obtainMessage(Phone.EVENT_IMEI_MAPPING_CHANGED);
+        imeiInfo.imei = FAKE_IMEI;
+        imeiInfo.svn = FAKE_IMEISV;
+        imeiInfo.type = ImeiInfo.ImeiType.SECONDARY;
+        AsyncResult.forMessage(message, imeiInfo, null);
+        mPhoneUT.handleMessage(message);
+        assertEquals(Phone.IMEI_TYPE_SECONDARY, mPhoneUT.getImeiType());
+        assertEquals(FAKE_IMEI, mPhoneUT.getImei());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 4858e91..6fc5616 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -1475,4 +1475,12 @@
     @Override
     public void cancelHandover(Message result, int callId) {
     }
+
+    /**
+     * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+     */
+    @Override
+    public void registerForImeiMappingChanged(Handler h, int what, Object obj) {
+
+    }
 }
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;