Merge "Update anomaly report UUID" into tm-qpr-dev
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index d27f400..cc2ca64 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -1106,6 +1106,8 @@
             removeMessages(EVENT_PRIMARY_TIMER_EXPIRED);
             mIsPrimaryTimerActive = false;
             mPrimaryTimerState = "";
+            transitionToCurrentState();
+            return;
         }
 
         if (mIsSecondaryTimerActive && !mSecondaryTimerState.equals(currentState)) {
@@ -1117,6 +1119,8 @@
             removeMessages(EVENT_SECONDARY_TIMER_EXPIRED);
             mIsSecondaryTimerActive = false;
             mSecondaryTimerState = "";
+            transitionToCurrentState();
+            return;
         }
 
         if (mIsPrimaryTimerActive || mIsSecondaryTimerActive) {
diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java
index c061e16..323e8b4 100644
--- a/src/java/com/android/internal/telephony/data/DataEvaluation.java
+++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java
@@ -195,50 +195,74 @@
     @VisibleForTesting
     public enum DataEvaluationReason {
         /** New request from the apps. */
-        NEW_REQUEST,
+        NEW_REQUEST(false),
         /** Data config changed. */
-        DATA_CONFIG_CHANGED,
+        DATA_CONFIG_CHANGED(true),
         /** SIM is loaded. */
-        SIM_LOADED,
+        SIM_LOADED(true),
         /** SIM is removed. */
-        SIM_REMOVAL,
+        SIM_REMOVAL(true),
         /** Data profiles changed. */
-        DATA_PROFILES_CHANGED,
+        DATA_PROFILES_CHANGED(true),
         /** When service state changes.(For now only considering data RAT and data registration). */
-        DATA_SERVICE_STATE_CHANGED,
+        DATA_SERVICE_STATE_CHANGED(true),
         /** When data is enabled or disabled (by user, carrier, thermal, etc...) */
-        DATA_ENABLED_CHANGED,
+        DATA_ENABLED_CHANGED(true),
         /** When data enabled overrides are changed (MMS always allowed, data on non-DDS sub). */
-        DATA_ENABLED_OVERRIDE_CHANGED,
+        DATA_ENABLED_OVERRIDE_CHANGED(true),
         /** When data roaming is enabled or disabled. */
-        ROAMING_ENABLED_CHANGED,
+        ROAMING_ENABLED_CHANGED(true),
         /** When voice call ended (for concurrent voice/data not supported RAT). */
-        VOICE_CALL_ENDED,
+        VOICE_CALL_ENDED(true),
         /** When network restricts or no longer restricts mobile data. */
-        DATA_RESTRICTED_CHANGED,
+        DATA_RESTRICTED_CHANGED(true),
         /** Network capabilities changed. The unsatisfied requests might have chances to attach. */
-        DATA_NETWORK_CAPABILITIES_CHANGED,
+        DATA_NETWORK_CAPABILITIES_CHANGED(true),
         /** When emergency call started or ended. */
-        EMERGENCY_CALL_CHANGED,
+        EMERGENCY_CALL_CHANGED(true),
         /** When data disconnected, re-evaluate later to see if data could be brought up again. */
-        RETRY_AFTER_DISCONNECTED,
+        RETRY_AFTER_DISCONNECTED(true),
         /** Data setup retry. */
-        DATA_RETRY,
+        DATA_RETRY(false),
         /** For handover evaluation, or for network tearing down after handover succeeds/fails. */
-        DATA_HANDOVER,
+        DATA_HANDOVER(true),
         /** Preferred transport changed. */
-        PREFERRED_TRANSPORT_CHANGED,
+        PREFERRED_TRANSPORT_CHANGED(true),
         /** Slice config changed. */
-        SLICE_CONFIG_CHANGED,
+        SLICE_CONFIG_CHANGED(true),
         /**
          * Single data network arbitration. On certain RATs, only one data network is allowed at the
          * same time.
          */
-        SINGLE_DATA_NETWORK_ARBITRATION,
+        SINGLE_DATA_NETWORK_ARBITRATION(true),
         /** Query from {@link TelephonyManager#isDataConnectivityPossible()}. */
-        EXTERNAL_QUERY,
+        EXTERNAL_QUERY(false),
         /** Tracking area code changed. */
-        TAC_CHANGED,
+        TAC_CHANGED(true);
+
+        /**
+         * {@code true} if the evaluation is due to environmental changes (i.e. SIM removal,
+         * registration state changes, etc....
+         */
+        private final boolean mIsConditionBased;
+
+        /**
+         * @return {@code true} if the evaluation is due to environmental changes (i.e. SIM removal,
+         * registration state changes, etc....
+         */
+        public boolean isConditionBased() {
+            return mIsConditionBased;
+        }
+
+        /**
+         * Constructor
+         *
+         * @param isConditionBased {@code true} if the evaluation is due to environmental changes
+         * (i.e. SIM removal, registration state changes, etc....)
+         */
+        DataEvaluationReason(boolean isConditionBased) {
+            mIsConditionBased = isConditionBased;
+        }
     }
 
     /** Disallowed reasons. There could be multiple reasons if it is not allowed. */
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index ab690d8..b4d49f7 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -3152,7 +3152,7 @@
                 && !mAttachedNetworkRequestList.isEmpty()) {
             TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);
             DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
-                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType);
+                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, true);
             // 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 a3cb5a7..bf3bab1 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -551,6 +551,15 @@
          */
         public void onInternetDataNetworkConnected(@NonNull List<DataProfile> dataProfiles) {}
 
+        /**
+         * Called when data network is connected.
+         *
+         * @param transport Transport for the connected network.
+         * @param dataProfile The data profile of the connected data network.
+         */
+        public void onDataNetworkConnected(@TransportType int transport,
+                @NonNull DataProfile dataProfile) {}
+
         /** Called when internet data network is disconnected. */
         public void onInternetDataNetworkDisconnected() {}
 
@@ -1426,7 +1435,7 @@
         if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
             evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
             evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest(
-                    networkRequest, getDataNetworkType(transport)));
+                    networkRequest, getDataNetworkType(transport), true));
             networkRequest.setEvaluation(evaluation);
             log(evaluation.toString());
             return evaluation;
@@ -1568,7 +1577,10 @@
 
         // Check if there is any compatible data profile
         DataProfile dataProfile = mDataProfileManager
-                .getDataProfileForNetworkRequest(networkRequest, getDataNetworkType(transport));
+                .getDataProfileForNetworkRequest(networkRequest, getDataNetworkType(transport),
+                        // If the evaluation is due to environmental changes, then we should ignore
+                        // the permanent failure reached earlier.
+                        reason.isConditionBased());
         if (dataProfile == null) {
             evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE);
         } else if (reason == DataEvaluationReason.NEW_REQUEST
@@ -2582,6 +2594,11 @@
      */
     private void onDataNetworkConnected(@NonNull DataNetwork dataNetwork) {
         logl("onDataNetworkConnected: " + dataNetwork);
+
+        mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
+                () -> callback.onDataNetworkConnected(dataNetwork.getTransport(),
+                        dataNetwork.getDataProfile())));
+
         mPreviousConnectedDataNetworkList.add(0, dataNetwork);
         // Preserve the connected data networks for debugging purposes.
         if (mPreviousConnectedDataNetworkList.size() > MAX_HISTORICAL_CONNECTED_DATA_NETWORKS) {
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index b038371..e8f1922 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -601,14 +601,18 @@
      *
      * @param networkRequest The network request.
      * @param networkType The current data network type.
+     * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
+     * This should be set to true for condition-based retry/setup.
      * @return The data profile. {@code null} if can't find any satisfiable data profile.
      */
     public @Nullable DataProfile getDataProfileForNetworkRequest(
-            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
+            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
+            boolean ignorePermanentFailure) {
         ApnSetting apnSetting = null;
         if (networkRequest.hasAttribute(TelephonyNetworkRequest
                 .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
-            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType);
+            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType,
+                    ignorePermanentFailure);
         }
 
         TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
@@ -667,10 +671,13 @@
      *
      * @param networkRequest The network request.
      * @param networkType The current data network type.
+     * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
+     * This should be set to true for condition-based retry/setup.
      * @return The APN setting. {@code null} if can't find any satisfiable data profile.
      */
     private @Nullable ApnSetting getApnSettingForNetworkRequest(
-            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
+            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
+            boolean ignorePermanentFailure) {
         if (!networkRequest.hasAttribute(
                 TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
             loge("Network request does not have APN setting attribute.");
@@ -713,6 +720,7 @@
                         && (dp.getApnSetting().getApnSetId()
                         == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                         || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
+                .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed())
                 .collect(Collectors.toList());
         if (dataProfiles.size() == 0) {
             log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId="
@@ -720,6 +728,15 @@
             return null;
         }
 
+        // Check if data profiles are permanently failed.
+        dataProfiles = dataProfiles.stream()
+                .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed())
+                .collect(Collectors.toList());
+        if (dataProfiles.size() == 0) {
+            log("The suitable data profiles are all in permanent failed state.");
+            return null;
+        }
+
         return dataProfiles.get(0).getApnSetting();
     }
 
@@ -752,7 +769,7 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                         .build(), mPhone);
-        return getDataProfileForNetworkRequest(networkRequest, networkType) != null;
+        return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null;
     }
 
      /**
@@ -1075,6 +1092,12 @@
         pw.println("Initial attach data profile=" + mInitialAttachDataProfile);
         pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting(
                 TelephonyManager.NETWORK_TYPE_LTE));
+        pw.println("Permanent failed profiles=");
+        pw.increaseIndent();
+        mAllDataProfiles.stream()
+                .filter(dp -> dp.getApnSetting() != null && dp.getApnSetting().getPermanentFailed())
+                .forEach(pw::println);
+        pw.decreaseIndent();
 
         pw.println("Local logs:");
         pw.increaseIndent();
diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java
index ec5ba1b..0faad2c 100644
--- a/src/java/com/android/internal/telephony/data/DataRetryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java
@@ -56,7 +56,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -315,10 +314,6 @@
                 }
             }
 
-            if (mMaxRetries == 0) {
-                mRetryIntervalsMillis = Collections.emptyList();
-            }
-
             if (mMaxRetries < 0) {
                 throw new IllegalArgumentException("Max retries should not be less than 0. "
                         + "mMaxRetries=" + mMaxRetries);
@@ -359,39 +354,45 @@
     }
 
     /**
-     * Represent a setup data network retry rule.
+     * Represent a rule for data setup retry.
      *
      * The syntax of the retry rule:
-     * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network
-     * capabilities are supported.
-     * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...],
-     * [maximum_retries=n]"
+     * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
+     *    are supported. If the capabilities are not specified, then the retry rule only applies
+     *    to the current failed APN used in setup data call request.
+     * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
      *
      * 2. Retry based on {@link DataFailCause}
-     * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...],
-     * [maximum_retries=n]"
+     * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
      *
      * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only
      *    APN-type network capabilities are supported.
      * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...],
      *     [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
      *
+     * 4. Permanent fail causes (no timer-based retry) on the current failed APN. Retry interval
+     *    is specified for retrying the next available APN.
+     * "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|65547|
+     *     2252|2253|2254, retry_interval=2500"
+     *
      * For example,
      * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached
      * network request is emergency, then retry data network setup every 1 second for up to 20
      * times.
      *
-     * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254
-     * , maximum_retries=0" means for those fail causes, never retry with timers. Note that
-     * when environment changes, retry can still happen.
-     *
      * "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
      * "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000"
-     * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s,
-     * 5s, 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
+     * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
+     * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
+     *
      */
     public static class DataSetupRetryRule extends DataRetryRule {
+        private static final String RULE_TAG_PERMANENT_FAIL_CAUSES = "permanent_fail_causes";
         private static final String RULE_TAG_CAPABILITIES = "capabilities";
+
+        /** {@code true} if this rule is for permanent fail causes. */
+        private boolean mIsPermanentFailCauseRule;
+
         /**
          * Constructor
          *
@@ -410,8 +411,23 @@
                 }
                 String key = tokens[0].trim();
                 String value = tokens[1].trim();
-                if (key.equals(RULE_TAG_CAPABILITIES)) {
-                    mNetworkCapabilities = DataUtils.getNetworkCapabilitiesFromString(value);
+                try {
+                    switch (key) {
+                        case RULE_TAG_PERMANENT_FAIL_CAUSES:
+                            mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*"))
+                                    .map(String::trim)
+                                    .map(Integer::valueOf)
+                                    .collect(Collectors.toSet());
+                            mIsPermanentFailCauseRule = true;
+                            break;
+                        case RULE_TAG_CAPABILITIES:
+                            mNetworkCapabilities = DataUtils
+                                    .getNetworkCapabilitiesFromString(value);
+                            break;
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e);
                 }
             }
 
@@ -434,6 +450,13 @@
         }
 
         /**
+         * @return {@code true} if this rule is for permanent fail causes.
+         */
+        public boolean isPermanentFailCauseRule() {
+            return mIsPermanentFailCauseRule;
+        }
+
+        /**
          * Check if this rule can be matched.
          *
          * @param networkCapability The network capability for matching.
@@ -949,10 +972,27 @@
         });
         dataNetworkController.registerDataNetworkControllerCallback(
                 new DataNetworkControllerCallback(this::post) {
+                    /**
+                     * Called when data service is bound.
+                     *
+                     * @param transport The transport of the data service.
+                     */
                     @Override
                     public void onDataServiceBound(@TransportType int transport) {
                         onReset(RESET_REASON_DATA_SERVICE_BOUND);
                     }
+
+                    /**
+                     * Called when data network is connected.
+                     *
+                     * @param transport Transport for the connected network.
+                     * @param dataProfile The data profile of the connected data network.
+                     */
+                    @Override
+                    public void onDataNetworkConnected(@TransportType int transport,
+                            @NonNull DataProfile dataProfile) {
+                        DataRetryManager.this.onDataNetworkConnected(transport, dataProfile);
+                    }
                 });
         mRil.registerForOn(this, EVENT_RADIO_ON, null);
         mRil.registerForModemReset(this, EVENT_MODEM_RESET, null);
@@ -1003,7 +1043,7 @@
                 } else if (ar.result instanceof DataProfile) {
                     dataProfile = (DataProfile) ar.result;
                 }
-                onDataProfileUnthrottled(dataProfile, apn, transport, true);
+                onDataProfileUnthrottled(dataProfile, apn, transport, true, true);
                 break;
             case EVENT_CANCEL_PENDING_HANDOVER_RETRY:
                 onCancelPendingHandoverRetry((DataNetwork) msg.obj);
@@ -1025,6 +1065,21 @@
     }
 
     /**
+     * Called when data network is connected.
+     *
+     * @param transport Transport for the connected network.
+     * @param dataProfile The data profile of the connected data network.
+     */
+    public void onDataNetworkConnected(@TransportType int transport,
+            @NonNull DataProfile dataProfile) {
+        if (dataProfile.getApnSetting() != null) {
+            dataProfile.getApnSetting().setPermanentFailed(false);
+        }
+
+        onDataProfileUnthrottled(dataProfile, null, transport, true, false);
+    }
+
+    /**
      * Evaluate if data setup retry is needed or not. If needed, retry will be scheduled
      * automatically after evaluation.
      *
@@ -1062,6 +1117,7 @@
             // ThrottleStatus is just for API backwards compatibility reason.
             updateThrottleStatus(dataProfile, requestList, null,
                     ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE);
+            return;
         } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) {
             // Network specifically asks retry the previous data profile again.
             DataSetupRetryEntry dataSetupRetryEntry = new DataSetupRetryEntry.Builder<>()
@@ -1075,67 +1131,89 @@
                     ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport,
                     dataSetupRetryEntry.retryElapsedTime);
             schedule(dataSetupRetryEntry);
-        } else {
-            // Network did not suggest any retry. Use the configured rules to perform retry.
-            logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList);
+            return;
+        }
 
-            // Support the legacy permanent failure configuration
-            if (DataFailCause.isPermanentFailure(mPhone.getContext(), cause, mPhone.getSubId())) {
-                log("Stopped timer-based retry. cause=" + DataFailCause.toString(cause));
+        // Network did not suggest any retry. Use the configured rules to perform retry.
+        logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList);
+
+        boolean retryScheduled = false;
+        List<NetworkRequestList> groupedNetworkRequestLists =
+                DataUtils.getGroupedNetworkRequestList(requestList);
+        for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) {
+            if (retryRule.isPermanentFailCauseRule() && retryRule.getFailCauses().contains(cause)) {
+                if (dataProfile.getApnSetting() != null) {
+                    dataProfile.getApnSetting().setPermanentFailed(true);
+
+                    // It seems strange to have retry timer in permanent failure rule, but since
+                    // in this case permanent failure is only applicable to the failed profile, so
+                    // we need to see if other profile can be selected for next data setup.
+                    log("Marked " + dataProfile.getApnSetting().getApnName() + " permanently "
+                            + "failed, but still schedule retry to see if another data profile "
+                            + "can be used for setup data.");
+                    // Schedule a data retry to see if another data profile could be selected.
+                    // If the same data profile is selected again, since it's marked as
+                    // permanent failure, it won't be used for setup data call.
+                    schedule(new DataSetupRetryEntry.Builder<>()
+                            .setRetryDelay(retryRule.getRetryIntervalsMillis().get(0))
+                            .setAppliedRetryRule(retryRule)
+                            .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS)
+                            .setTransport(transport)
+                            .setNetworkRequestList(requestList)
+                            .build());
+                } else {
+                    // For TD-based data profile, do not do anything for now. Should expand this in
+                    // the future if needed.
+                    log("Stopped timer-based retry for TD-based data profile. Will retry only when "
+                            + "environment changes.");
+                }
                 return;
             }
-
-            boolean retryScheduled = false;
-            List<NetworkRequestList> groupedNetworkRequestLists =
-                    DataUtils.getGroupedNetworkRequestList(requestList);
             for (NetworkRequestList networkRequestList : groupedNetworkRequestLists) {
                 int capability = networkRequestList.get(0).getApnTypeNetworkCapability();
-
-                for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) {
-                    if (retryRule.canBeMatched(capability, cause)) {
-                        // Check if there is already a similar network request retry scheduled.
-                        if (isSimilarNetworkRequestRetryScheduled(
-                                networkRequestList.get(0), transport)) {
-                            log(networkRequestList.get(0) + " already had similar retry "
-                                    + "scheduled.");
-                            return;
-                        }
-
-                        int failedCount = getRetryFailedCount(capability, retryRule);
-                        log("For capability " + DataUtils.networkCapabilityToString(capability)
-                                + ", found matching rule " + retryRule + ", failed count="
-                                + failedCount);
-                        if (failedCount == retryRule.getMaxRetries()) {
-                            log("Data retry failed for " + failedCount + " times. Stopped "
-                                    + "timer-based data retry for "
-                                    + DataUtils.networkCapabilityToString(capability)
-                                    + ". Condition-based retry will still happen when condition "
-                                    + "changes.");
-                            return;
-                        }
-
-                        retryDelayMillis = retryRule.getRetryIntervalsMillis().get(
-                                Math.min(failedCount, retryRule
-                                        .getRetryIntervalsMillis().size() - 1));
-
-                        // Schedule a data retry.
-                        schedule(new DataSetupRetryEntry.Builder<>()
-                                .setRetryDelay(retryDelayMillis)
-                                .setAppliedRetryRule(retryRule)
-                                .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS)
-                                .setTransport(transport)
-                                .setNetworkRequestList(networkRequestList)
-                                .build());
-                        retryScheduled = true;
-                        break;
+                if (retryRule.canBeMatched(capability, cause)) {
+                    // Check if there is already a similar network request retry scheduled.
+                    if (isSimilarNetworkRequestRetryScheduled(
+                            networkRequestList.get(0), transport)) {
+                        log(networkRequestList.get(0) + " already had similar retry "
+                                + "scheduled.");
+                        return;
                     }
+
+                    int failedCount = getRetryFailedCount(capability, retryRule);
+                    log("For capability " + DataUtils.networkCapabilityToString(capability)
+                            + ", found matching rule " + retryRule + ", failed count="
+                            + failedCount);
+                    if (failedCount == retryRule.getMaxRetries()) {
+                        log("Data retry failed for " + failedCount + " times. Stopped "
+                                + "timer-based data retry for "
+                                + DataUtils.networkCapabilityToString(capability)
+                                + ". Condition-based retry will still happen when condition "
+                                + "changes.");
+                        return;
+                    }
+
+                    retryDelayMillis = retryRule.getRetryIntervalsMillis().get(
+                            Math.min(failedCount, retryRule
+                                    .getRetryIntervalsMillis().size() - 1));
+
+                    // Schedule a data retry.
+                    schedule(new DataSetupRetryEntry.Builder<>()
+                            .setRetryDelay(retryDelayMillis)
+                            .setAppliedRetryRule(retryRule)
+                            .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS)
+                            .setTransport(transport)
+                            .setNetworkRequestList(networkRequestList)
+                            .build());
+                    retryScheduled = true;
+                    break;
                 }
             }
+        }
 
-            if (!retryScheduled) {
-                log("onEvaluateDataSetupRetry: Did not match any retry rule. Stop timer-based "
-                        + "retry.");
-            }
+        if (!retryScheduled) {
+            log("onEvaluateDataSetupRetry: Did not match any retry rule. Stop timer-based "
+                    + "retry.");
         }
     }
 
@@ -1224,7 +1302,7 @@
             DataProfile dataProfile = dataThrottlingEntry.dataProfile;
             String apn = dataProfile.getApnSetting() != null
                     ? dataProfile.getApnSetting().getApnName() : null;
-            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false);
+            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false, true);
         }
 
         mDataThrottlingEntries.clear();
@@ -1383,9 +1461,10 @@
      * When this is set, {@code dataProfile} must be {@code null}.
      * @param transport The transport that this unthrottling request is on.
      * @param remove Whether to remove unthrottled entries from the list of entries.
+     * @param retry Whether schedule data setup retry after unthrottling.
      */
     private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn,
-            int transport, boolean remove) {
+            @TransportType int transport, boolean remove, boolean retry) {
         log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn
                 + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)
                 + ", remove=" + remove);
@@ -1402,6 +1481,7 @@
             Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream();
             stream = stream.filter(entry -> entry.expirationTimeMillis > now);
             if (dataProfile.getApnSetting() != null) {
+                dataProfile.getApnSetting().setPermanentFailed(false);
                 stream = stream
                         .filter(entry -> entry.dataProfile.getApnSetting() != null)
                         .filter(entry -> entry.dataProfile.getApnSetting().getApnName()
@@ -1458,21 +1538,23 @@
 
         logl("onDataProfileUnthrottled: Removing the following throttling entries. "
                 + dataUnthrottlingEntries);
-        for (DataThrottlingEntry entry : dataUnthrottlingEntries) {
-            if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
+        if (retry) {
+            for (DataThrottlingEntry entry : dataUnthrottlingEntries) {
                 // Immediately retry after unthrottling.
-                schedule(new DataSetupRetryEntry.Builder<>()
-                        .setDataProfile(entry.dataProfile)
-                        .setTransport(entry.transport)
-                        .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE)
-                        .setNetworkRequestList(entry.networkRequestList)
-                        .setRetryDelay(0)
-                        .build());
-            } else if (entry.retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) {
-                schedule(new DataHandoverRetryEntry.Builder<>()
-                        .setDataNetwork(entry.dataNetwork)
-                        .setRetryDelay(0)
-                        .build());
+                if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
+                    schedule(new DataSetupRetryEntry.Builder<>()
+                            .setDataProfile(entry.dataProfile)
+                            .setTransport(entry.transport)
+                            .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE)
+                            .setNetworkRequestList(entry.networkRequestList)
+                            .setRetryDelay(0)
+                            .build());
+                } else if (entry.retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) {
+                    schedule(new DataHandoverRetryEntry.Builder<>()
+                            .setDataNetwork(entry.dataNetwork)
+                            .setRetryDelay(0)
+                            .build());
+                }
             }
         }
         if (remove) {
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 867f999..4c6bff9 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -357,9 +357,9 @@
     public synchronized void onRilSrvccStateChanged(int state) {
         List<Connection> handoverConnections = null;
         if (mPhone.getImsPhone() != null) {
-            loge("onRilSrvccStateChanged: ImsPhone is null");
-        } else {
             handoverConnections = mPhone.getImsPhone().getHandoverConnection();
+        } else {
+            loge("onRilSrvccStateChanged: ImsPhone is null");
         }
         List<Integer> imsConnIds;
         if (handoverConnections == null) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java
index 46d1f0a..7ee5e23 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java
@@ -38,6 +38,7 @@
 
 public class DataCallResponseTest extends AndroidTestCase {
     public static final String FAKE_DNN = "FAKE_DNN";
+    public static final String FAKE_DNN_2 = "FAKE_DNN_2";
     // 97a498e3fc925c9489860333d06e4e470a454e5445525052495345.
     // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1]
     public static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92,
@@ -82,7 +83,7 @@
     }
 
     @SmallTest
-    public void testEquals() {
+    public void testEqualsAndHashCode() {
         DataCallResponse response = new DataCallResponse.Builder()
                 .setCause(0)
                 .setRetryDurationMillis(-1L)
@@ -123,6 +124,7 @@
 
         assertEquals(response, response);
         assertEquals(response, response1);
+        assertEquals(response.hashCode(), response1.hashCode());
 
         DataCallResponse response2 = new DataCallResponse.Builder()
                 .setCause(1)
@@ -141,12 +143,39 @@
                         InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
                 .setMtuV4(1441)
                 .setMtuV6(1440)
-                .setTrafficDescriptors(
-                        Arrays.asList(new TrafficDescriptor("FAKE_DNN_2", FAKE_OS_APP_ID_2)))
+                .setTrafficDescriptors(Arrays.asList(
+                        new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID),
+                        new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2)))
                 .build();
 
         assertNotSame(response1, response2);
         assertNotSame(response1, null);
         assertNotSame(response1, new String[1]);
+        assertNotSame(response1.hashCode(), response2.hashCode());
+
+        DataCallResponse response3 = new DataCallResponse.Builder()
+                .setCause(1)
+                .setRetryDurationMillis(-1L)
+                .setId(1)
+                .setLinkStatus(3)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS),
+                        InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(Arrays.asList(
+                        InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS),
+                        InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1441)
+                .setMtuV6(1440)
+                .setTrafficDescriptors(Arrays.asList(
+                        new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2),
+                        new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID)))
+                .build();
+
+        assertEquals(response2, response3);
+        assertEquals(response2.hashCode(), response3.hashCode());
     }
 }
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 fb1f5b5..399fd9f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -181,6 +181,7 @@
                     .setRoamingProtocol(ApnSetting.PROTOCOL_IP)
                     .setCarrierEnabled(true)
                     .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                            | TelephonyManager.NETWORK_TYPE_BITMASK_NR
                             | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN
                             | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT))
                     .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE
@@ -629,8 +630,8 @@
                 CarrierConfigManager.KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY,
                 new String[]{
                         "capabilities=eims, retry_interval=1000, maximum_retries=20",
-                        "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|"
-                                + "2254, maximum_retries=0", // No retry for those causes
+                        "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|"
+                                + "-3|65543|65547|2252|2253|2254, retry_interval=2500",
                         "capabilities=mms|supl|cbs, retry_interval=2000",
                         "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
                                 + "5000|10000|15000|20000|40000|60000|120000|240000|"
@@ -793,8 +794,7 @@
                 linkBandwidthEstimatorCallbackCaptor.capture());
         mLinkBandwidthEstimatorCallback = linkBandwidthEstimatorCallbackCaptor.getValue();
 
-        List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile,
-                mImsCellularDataProfile,
+        List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile, mImsCellularDataProfile,
                 mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile,
                 mTetheringDataProfile);
 
@@ -827,12 +827,15 @@
             TelephonyNetworkRequest networkRequest =
                     (TelephonyNetworkRequest) invocation.getArguments()[0];
             int networkType = (int) invocation.getArguments()[1];
+            boolean ignorePermanentFailure = (boolean) invocation.getArguments()[2];
 
             for (DataProfile dataProfile : profiles) {
                 if (dataProfile.canSatisfy(networkRequest.getCapabilities())
                         && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0
                         || (dataProfile.getApnSetting().getNetworkTypeBitmask()
-                        & ServiceState.getBitmaskForTech(networkType)) != 0)) {
+                        & ServiceState.getBitmaskForTech(networkType)) != 0)
+                        && (ignorePermanentFailure || (dataProfile.getApnSetting() != null
+                        && !dataProfile.getApnSetting().getPermanentFailed()))) {
                     return dataProfile;
                 }
             }
@@ -840,7 +843,7 @@
                     + TelephonyManager.getNetworkTypeName(networkType));
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean());
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(anyInt());
@@ -1123,7 +1126,7 @@
                     + TelephonyManager.getNetworkTypeName(networkType));
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean());
 
         // verify the network still connects
         verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any());
@@ -1167,7 +1170,8 @@
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager,
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
-                .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt());
+                .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
+                        anyBoolean());
 
         mDataNetworkControllerUT.addNetworkRequest(
                 createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
@@ -1358,7 +1362,8 @@
 
         // Now RAT changes from UMTS to GSM
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM));
+                any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM),
+                anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyAllDataDisconnected();
@@ -1369,13 +1374,15 @@
         Mockito.clearInvocations(mMockedDataNetworkControllerCallback);
         // Now RAT changes from GSM to UMTS
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS));
+                any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS),
+                anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager)
-                .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt());
+                .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
+                        anyBoolean());
         // Now RAT changes from UMTS to LTE
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
@@ -2592,6 +2599,34 @@
         verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(),
                 any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
                 any(), any(), anyBoolean(), any(Message.class));
+
+        Mockito.clearInvocations(mMockedWwanDataServiceManager);
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        processAllFutureMessages();
+
+        // Even receiving a new network request, setup data call should not be sent.
+        verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(),
+                any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
+                any(), any(), anyBoolean(), any(Message.class));
+        // APN should be marked as permanent failure.
+        assertThat(mGeneralPurposeDataProfile.getApnSetting().getPermanentFailed()).isTrue();
+    }
+
+    @Test
+    public void testSetupDataNetworkConditionChangesAfterPermanentFailure() throws Exception {
+        testSetupDataNetworkPermanentFailure();
+
+        setSuccessfulSetupDataResponse(mMockedDataServiceManagers
+                .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 1);
+
+        // From LTE to NR
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_NR,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // condition change should trigger setup data, even though previously the APN has been
+        // marked as permanent failure.
+        verifyInternetConnected();
     }
 
     @Test
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 7c7befa..7dda6c1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -492,7 +492,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -503,7 +503,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -513,7 +513,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(IMS_APN);
 
@@ -522,7 +522,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dp).isNull();
 
         doReturn(new NetworkRegistrationInfo.Builder()
@@ -535,7 +535,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_NR);
+                TelephonyManager.NETWORK_TYPE_NR, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(TETHERING_APN);
     }
@@ -547,7 +547,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_GSM);
+                TelephonyManager.NETWORK_TYPE_GSM, false);
         // Should not find data profile due to RAT incompatible.
         assertThat(dp).isNull();
     }
@@ -559,14 +559,14 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, 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);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
     }
 
@@ -577,7 +577,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -590,7 +590,7 @@
                 .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
                 0, NetworkRequest.Type.REQUEST), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -606,7 +606,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -622,7 +622,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -639,7 +639,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         dataProfile.setPreferred(true);
@@ -648,7 +648,7 @@
 
         // See if the same one can be returned.
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
     }
 
@@ -715,7 +715,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile).isNull();
 
         tnr = new TelephonyNetworkRequest(
@@ -723,7 +723,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
 
         tnr = new TelephonyNetworkRequest(
@@ -731,7 +731,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("ims");
     }
 
@@ -762,7 +762,7 @@
                 new TelephonyNetworkRequest(new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone),
-                TelephonyManager.NETWORK_TYPE_LTE);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN);
     }
 
@@ -774,7 +774,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);
+                TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
     }
 
@@ -905,7 +905,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                 .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
 
         assertThat(dataProfile.getApn()).isEqualTo("sos");
         assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos");
@@ -922,7 +922,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         dataProfile.setPreferred(true);
@@ -970,7 +970,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
 
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
@@ -983,7 +983,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
index 4fbc31c..348d96f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
+import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
 import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryRule;
 import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback;
 import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryRule;
@@ -124,9 +125,6 @@
             .setPreferred(false)
             .build();
 
-    private final List<DataProfile> mAllDataProfileList = List.of(mDataProfile1, mDataProfile2,
-            mDataProfile3);
-
     // Mocked classes
     private DataRetryManagerCallback mDataRetryManagerCallbackMock;
 
@@ -134,6 +132,8 @@
 
     private DataConfigManagerCallback mDataConfigManagerCallback;
 
+    private DataNetworkControllerCallback mDataNetworkControllerCallback;
+
     @Before
     public void setUp() throws Exception {
         logd("DataRetryManagerTest +Setup!");
@@ -156,6 +156,12 @@
         verify(mDataConfigManager).registerCallback(dataConfigManagerCallbackCaptor.capture());
         mDataConfigManagerCallback = dataConfigManagerCallbackCaptor.getValue();
 
+        ArgumentCaptor<DataNetworkControllerCallback> dataNetworkControllerCallbackCaptor =
+                ArgumentCaptor.forClass(DataNetworkControllerCallback.class);
+        verify(mDataNetworkController).registerDataNetworkControllerCallback(
+                dataNetworkControllerCallbackCaptor.capture());
+        mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue();
+
         logd("DataRetryManagerTest -Setup!");
     }
 
@@ -183,7 +189,6 @@
         assertThat(rule.getMaxRetries()).isEqualTo(0);
         assertThat(rule.getFailCauses()).containsExactly(8, 27, 28, 29, 30, 32, 33, 35, 50,
                 51, 111, -5, -6, 65537, 65538, -3, 2253, 2254);
-        assertThat(rule.getRetryIntervalsMillis()).isEmpty();
 
         ruleString = "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|  3000|"
                 + "    5000|  10000 | 15000|        20000|40000|60000|  120000|240000  |"
@@ -393,15 +398,15 @@
     @Test
     public void testDataSetupRetryPermanentFailure() {
         DataSetupRetryRule retryRule = new DataSetupRetryRule(
-                "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|"
-                        + "2254, maximum_retries=0");
+                "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|"
+                        + "65547|2252|2253|2254, retry_interval=2500");
         doReturn(Collections.singletonList(retryRule)).when(mDataConfigManager)
                 .getDataSetupRetryRules();
         mDataConfigManagerCallback.onCarrierConfigChanged();
         processAllMessages();
 
-
         NetworkRequest request = new NetworkRequest.Builder()
+
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
@@ -412,8 +417,17 @@
                 DataCallResponse.RETRY_DURATION_UNDEFINED);
         processAllFutureMessages();
 
-        verify(mDataRetryManagerCallbackMock, never())
+        // Permanent failure is only applicable to the failed APN. Retry should still happen if
+        // there are other APNs.
+        verify(mDataRetryManagerCallbackMock)
                 .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class));
+        assertThat(mDataProfile1.getApnSetting().getPermanentFailed()).isTrue();
+
+        // When condition changes, data will still be retried. As soon as data network is connected,
+        // we should clear the previous permanent failure.
+        mDataNetworkControllerCallback.onDataNetworkConnected(
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mDataProfile1);
+        assertThat(mDataProfile1.getApnSetting().getPermanentFailed()).isFalse();
     }
 
     @Test
@@ -607,7 +621,6 @@
         assertThat(rule.getMaxRetries()).isEqualTo(0);
         assertThat(rule.getFailCauses()).containsExactly(8, 27, 28, 29, 30, 32, 33, 35, 50,
                 51, 111, -5, -6, 65537, 65538, -3, 2253, 2254);
-        assertThat(rule.getRetryIntervalsMillis()).isEmpty();
 
         ruleString = "retry_interval=1000|2000|4000|8000|16000, maximum_retries=5";
         rule = new DataHandoverRetryRule(ruleString);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
index d2223f7..fd6cbff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
@@ -81,7 +81,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
@@ -909,7 +908,6 @@
 
     @Test
     @SmallTest
-    @Ignore("b/256234604")
     public void singleImsCall_ratSwitchToUnknown() {
         setServiceState(mServiceState, TelephonyManager.NETWORK_TYPE_LTE);
         doReturn(true).when(mImsConnection0).isIncoming();
@@ -923,6 +921,7 @@
                         VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT,
                         TelephonyManager.NETWORK_TYPE_LTE,
                         ImsReasonInfo.CODE_USER_TERMINATED);
+        expectedCall.setupDuration = 1;
         expectedCall.setupDurationMillis = 80;
         expectedCall.setupFailed = false;
         expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_AMR;