Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d6966cc authored by Jack Yu's avatar Jack Yu
Browse files

Fixed permananent failure behaviors

1. Non-conditional based evaluations will no longer trigger
   setup data if the APN was marked as permanent failure earlier.
   Only environmental changes can result in data setup.
2. Permanent failure can be only applied to the failed APN. When
   this happens, frameworks retries the next non-permanent-failed
   APN.

Fix: 254752857
Fix: 249908875
Test: Manual (verified on JP carrier) + atest FrameworksTelephonyTests
     + Basic testing.
Merged-In: Ic147c44b0729e8204cb494eb80932ef2c11f9861
Change-Id: Ic147c44b0729e8204cb494eb80932ef2c11f9861
parent 9b138dc2
Loading
Loading
Loading
Loading
+45 −21
Original line number Original line Diff line number Diff line
@@ -195,50 +195,74 @@ public class DataEvaluation {
    @VisibleForTesting
    @VisibleForTesting
    public enum DataEvaluationReason {
    public enum DataEvaluationReason {
        /** New request from the apps. */
        /** New request from the apps. */
        NEW_REQUEST,
        NEW_REQUEST(false),
        /** Data config changed. */
        /** Data config changed. */
        DATA_CONFIG_CHANGED,
        DATA_CONFIG_CHANGED(true),
        /** SIM is loaded. */
        /** SIM is loaded. */
        SIM_LOADED,
        SIM_LOADED(true),
        /** SIM is removed. */
        /** SIM is removed. */
        SIM_REMOVAL,
        SIM_REMOVAL(true),
        /** Data profiles changed. */
        /** Data profiles changed. */
        DATA_PROFILES_CHANGED,
        DATA_PROFILES_CHANGED(true),
        /** When service state changes.(For now only considering data RAT and data registration). */
        /** 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...) */
        /** 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). */
        /** 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. */
        /** 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). */
        /** 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. */
        /** 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. */
        /** 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. */
        /** 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. */
        /** 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 setup retry. */
        DATA_RETRY,
        DATA_RETRY(false),
        /** For handover evaluation, or for network tearing down after handover succeeds/fails. */
        /** 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,
        PREFERRED_TRANSPORT_CHANGED(true),
        /** Slice config changed. */
        /** 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
         * Single data network arbitration. On certain RATs, only one data network is allowed at the
         * same time.
         * same time.
         */
         */
        SINGLE_DATA_NETWORK_ARBITRATION,
        SINGLE_DATA_NETWORK_ARBITRATION(true),
        /** Query from {@link TelephonyManager#isDataConnectivityPossible()}. */
        /** Query from {@link TelephonyManager#isDataConnectivityPossible()}. */
        EXTERNAL_QUERY,
        EXTERNAL_QUERY(false),
        /** Tracking area code changed. */
        /** 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. */
    /** Disallowed reasons. There could be multiple reasons if it is not allowed. */
+1 −1
Original line number Original line Diff line number Diff line
@@ -3131,7 +3131,7 @@ public class DataNetwork extends StateMachine {
                && !mAttachedNetworkRequestList.isEmpty()) {
                && !mAttachedNetworkRequestList.isEmpty()) {
            TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);
            TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);
            DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
            DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType);
                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, true);
            // Some carriers have different profiles between cellular and IWLAN. We need to
            // Some carriers have different profiles between cellular and IWLAN. We need to
            // dynamically switch profile, but only when those profiles have same APN name.
            // dynamically switch profile, but only when those profiles have same APN name.
            if (dataProfile != null && dataProfile.getApnSetting() != null
            if (dataProfile != null && dataProfile.getApnSetting() != null
+19 −2
Original line number Original line Diff line number Diff line
@@ -551,6 +551,15 @@ public class DataNetworkController extends Handler {
         */
         */
        public void onInternetDataNetworkConnected(@NonNull List<DataProfile> dataProfiles) {}
        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. */
        /** Called when internet data network is disconnected. */
        public void onInternetDataNetworkDisconnected() {}
        public void onInternetDataNetworkDisconnected() {}


@@ -1426,7 +1435,7 @@ public class DataNetworkController extends Handler {
        if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
        if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
            evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
            evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
            evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest(
            evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest(
                    networkRequest, getDataNetworkType(transport)));
                    networkRequest, getDataNetworkType(transport), true));
            networkRequest.setEvaluation(evaluation);
            networkRequest.setEvaluation(evaluation);
            log(evaluation.toString());
            log(evaluation.toString());
            return evaluation;
            return evaluation;
@@ -1575,7 +1584,10 @@ public class DataNetworkController extends Handler {
            networkType = mServiceState.getVoiceNetworkType();
            networkType = mServiceState.getVoiceNetworkType();
        }
        }
        DataProfile dataProfile = mDataProfileManager
        DataProfile dataProfile = mDataProfileManager
                .getDataProfileForNetworkRequest(networkRequest, networkType);
                .getDataProfileForNetworkRequest(networkRequest, networkType,
                        // If the evaluation is due to environmental changes, then we should ignore
                        // the permanent failure reached earlier.
                        reason.isConditionBased());
        if (dataProfile == null) {
        if (dataProfile == null) {
            evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE);
            evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE);
        } else if (reason == DataEvaluationReason.NEW_REQUEST
        } else if (reason == DataEvaluationReason.NEW_REQUEST
@@ -2604,6 +2616,11 @@ public class DataNetworkController extends Handler {
     */
     */
    private void onDataNetworkConnected(@NonNull DataNetwork dataNetwork) {
    private void onDataNetworkConnected(@NonNull DataNetwork dataNetwork) {
        logl("onDataNetworkConnected: " + dataNetwork);
        logl("onDataNetworkConnected: " + dataNetwork);

        mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                () -> callback.onDataNetworkConnected(dataNetwork.getTransport(),
                        dataNetwork.getDataProfile())));

        mPreviousConnectedDataNetworkList.add(0, dataNetwork);
        mPreviousConnectedDataNetworkList.add(0, dataNetwork);
        // Preserve the connected data networks for debugging purposes.
        // Preserve the connected data networks for debugging purposes.
        if (mPreviousConnectedDataNetworkList.size() > MAX_HISTORICAL_CONNECTED_DATA_NETWORKS) {
        if (mPreviousConnectedDataNetworkList.size() > MAX_HISTORICAL_CONNECTED_DATA_NETWORKS) {
+27 −4
Original line number Original line Diff line number Diff line
@@ -621,14 +621,18 @@ public class DataProfileManager extends Handler {
     *
     *
     * @param networkRequest The network request.
     * @param networkRequest The network request.
     * @param networkType The current data network type.
     * @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.
     * @return The data profile. {@code null} if can't find any satisfiable data profile.
     */
     */
    public @Nullable DataProfile getDataProfileForNetworkRequest(
    public @Nullable DataProfile getDataProfileForNetworkRequest(
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
            boolean ignorePermanentFailure) {
        ApnSetting apnSetting = null;
        ApnSetting apnSetting = null;
        if (networkRequest.hasAttribute(TelephonyNetworkRequest
        if (networkRequest.hasAttribute(TelephonyNetworkRequest
                .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
                .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType);
            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType,
                    ignorePermanentFailure);
        }
        }


        TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
        TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
@@ -687,10 +691,13 @@ public class DataProfileManager extends Handler {
     *
     *
     * @param networkRequest The network request.
     * @param networkRequest The network request.
     * @param networkType The current data network type.
     * @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.
     * @return The APN setting. {@code null} if can't find any satisfiable data profile.
     */
     */
    private @Nullable ApnSetting getApnSettingForNetworkRequest(
    private @Nullable ApnSetting getApnSettingForNetworkRequest(
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
            boolean ignorePermanentFailure) {
        if (!networkRequest.hasAttribute(
        if (!networkRequest.hasAttribute(
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
            loge("Network request does not have APN setting attribute.");
            loge("Network request does not have APN setting attribute.");
@@ -733,6 +740,7 @@ public class DataProfileManager extends Handler {
                        && (dp.getApnSetting().getApnSetId()
                        && (dp.getApnSetting().getApnSetId()
                        == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                        == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                        || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
                        || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
                .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed())
                .collect(Collectors.toList());
                .collect(Collectors.toList());
        if (dataProfiles.size() == 0) {
        if (dataProfiles.size() == 0) {
            log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId="
            log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId="
@@ -740,6 +748,15 @@ public class DataProfileManager extends Handler {
            return null;
            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();
        return dataProfiles.get(0).getApnSetting();
    }
    }


@@ -772,7 +789,7 @@ public class DataProfileManager extends Handler {
                new NetworkRequest.Builder()
                new NetworkRequest.Builder()
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                        .build(), mPhone);
                        .build(), mPhone);
        return getDataProfileForNetworkRequest(networkRequest, networkType) != null;
        return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null;
    }
    }


     /**
     /**
@@ -1094,6 +1111,12 @@ public class DataProfileManager extends Handler {
        pw.println("Initial attach data profile=" + mInitialAttachDataProfile);
        pw.println("Initial attach data profile=" + mInitialAttachDataProfile);
        pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting(
        pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting(
                TelephonyManager.NETWORK_TYPE_LTE));
                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.println("Local logs:");
        pw.increaseIndent();
        pw.increaseIndent();
+170 −88
Original line number Original line Diff line number Diff line
@@ -56,7 +56,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Locale;
import java.util.Locale;
import java.util.Objects;
import java.util.Objects;
@@ -315,10 +314,6 @@ public class DataRetryManager extends Handler {
                }
                }
            }
            }


            if (mMaxRetries == 0) {
                mRetryIntervalsMillis = Collections.emptyList();
            }

            if (mMaxRetries < 0) {
            if (mMaxRetries < 0) {
                throw new IllegalArgumentException("Max retries should not be less than 0. "
                throw new IllegalArgumentException("Max retries should not be less than 0. "
                        + "mMaxRetries=" + mMaxRetries);
                        + "mMaxRetries=" + mMaxRetries);
@@ -359,39 +354,45 @@ public class DataRetryManager extends Handler {
    }
    }


    /**
    /**
     * Represent a setup data network retry rule.
     * Represent a rule for data setup retry.
     *
     *
     * The syntax of the retry rule:
     * The syntax of the retry rule:
     * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network
     * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
     * capabilities are supported.
     *    are supported. If the capabilities are not specified, then the retry rule only applies
     * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...],
     *    to the current failed APN used in setup data call request.
     * [maximum_retries=n]"
     * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
     *
     *
     * 2. Retry based on {@link DataFailCause}
     * 2. Retry based on {@link DataFailCause}
     * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...],
     * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
     * [maximum_retries=n]"
     *
     *
     * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only
     * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only
     *    APN-type network capabilities are supported.
     *    APN-type network capabilities are supported.
     * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...],
     * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...],
     *     [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
     *     [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,
     * For example,
     * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached
     * "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
     * network request is emergency, then retry data network setup every 1 second for up to 20
     * times.
     * 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|"
     * "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
     * "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000"
     * "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,
     * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
     * 5s, 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
     * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
     *
     */
     */
    public static class DataSetupRetryRule extends DataRetryRule {
    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";
        private static final String RULE_TAG_CAPABILITIES = "capabilities";

        /** {@code true} if this rule is for permanent fail causes. */
        private boolean mIsPermanentFailCauseRule;

        /**
        /**
         * Constructor
         * Constructor
         *
         *
@@ -410,8 +411,23 @@ public class DataRetryManager extends Handler {
                }
                }
                String key = tokens[0].trim();
                String key = tokens[0].trim();
                String value = tokens[1].trim();
                String value = tokens[1].trim();
                if (key.equals(RULE_TAG_CAPABILITIES)) {
                try {
                    mNetworkCapabilities = DataUtils.getNetworkCapabilitiesFromString(value);
                    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);
                }
                }
            }
            }


@@ -433,6 +449,13 @@ public class DataRetryManager extends Handler {
            return mNetworkCapabilities;
            return mNetworkCapabilities;
        }
        }


        /**
         * @return {@code true} if this rule is for permanent fail causes.
         */
        public boolean isPermanentFailCauseRule() {
            return mIsPermanentFailCauseRule;
        }

        /**
        /**
         * Check if this rule can be matched.
         * Check if this rule can be matched.
         *
         *
@@ -949,10 +972,27 @@ public class DataRetryManager extends Handler {
        });
        });
        dataNetworkController.registerDataNetworkControllerCallback(
        dataNetworkController.registerDataNetworkControllerCallback(
                new DataNetworkControllerCallback(this::post) {
                new DataNetworkControllerCallback(this::post) {
                    /**
                     * Called when data service is bound.
                     *
                     * @param transport The transport of the data service.
                     */
                    @Override
                    @Override
                    public void onDataServiceBound(@TransportType int transport) {
                    public void onDataServiceBound(@TransportType int transport) {
                        onReset(RESET_REASON_DATA_SERVICE_BOUND);
                        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.registerForOn(this, EVENT_RADIO_ON, null);
        mRil.registerForModemReset(this, EVENT_MODEM_RESET, null);
        mRil.registerForModemReset(this, EVENT_MODEM_RESET, null);
@@ -1001,7 +1041,7 @@ public class DataRetryManager extends Handler {
                } else if (ar.result instanceof DataProfile) {
                } else if (ar.result instanceof DataProfile) {
                    dataProfile = (DataProfile) ar.result;
                    dataProfile = (DataProfile) ar.result;
                }
                }
                onDataProfileUnthrottled(dataProfile, apn, transport, true);
                onDataProfileUnthrottled(dataProfile, apn, transport, true, true);
                break;
                break;
            case EVENT_CANCEL_PENDING_HANDOVER_RETRY:
            case EVENT_CANCEL_PENDING_HANDOVER_RETRY:
                onCancelPendingHandoverRetry((DataNetwork) msg.obj);
                onCancelPendingHandoverRetry((DataNetwork) msg.obj);
@@ -1034,6 +1074,21 @@ public class DataRetryManager extends Handler {
                + ", mDataHandoverRetryRuleList=" + mDataHandoverRetryRuleList);
                + ", mDataHandoverRetryRuleList=" + mDataHandoverRetryRuleList);
    }
    }


    /**
     * 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
     * Evaluate if data setup retry is needed or not. If needed, retry will be scheduled
     * automatically after evaluation.
     * automatically after evaluation.
@@ -1072,6 +1127,7 @@ public class DataRetryManager extends Handler {
            // ThrottleStatus is just for API backwards compatibility reason.
            // ThrottleStatus is just for API backwards compatibility reason.
            updateThrottleStatus(dataProfile, requestList, null,
            updateThrottleStatus(dataProfile, requestList, null,
                    ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE);
                    ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE);
            return;
        } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) {
        } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) {
            // Network specifically asks retry the previous data profile again.
            // Network specifically asks retry the previous data profile again.
            DataSetupRetryEntry dataSetupRetryEntry = new DataSetupRetryEntry.Builder<>()
            DataSetupRetryEntry dataSetupRetryEntry = new DataSetupRetryEntry.Builder<>()
@@ -1085,23 +1141,46 @@ public class DataRetryManager extends Handler {
                    ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport,
                    ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport,
                    dataSetupRetryEntry.retryElapsedTime);
                    dataSetupRetryEntry.retryElapsedTime);
            schedule(dataSetupRetryEntry);
            schedule(dataSetupRetryEntry);
        } else {
            // Network did not suggest any retry. Use the configured rules to perform retry.
            logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList);

            // Support the legacy permanent failure configuration
            if (DataFailCause.isPermanentFailure(mPhone.getContext(), cause, mPhone.getSubId())) {
                log("Stopped timer-based retry. cause=" + DataFailCause.toString(cause));
            return;
            return;
        }
        }


        // Network did not suggest any retry. Use the configured rules to perform retry.
        logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList);

        boolean retryScheduled = false;
        boolean retryScheduled = false;
        List<NetworkRequestList> groupedNetworkRequestLists =
        List<NetworkRequestList> groupedNetworkRequestLists =
                DataUtils.getGroupedNetworkRequestList(requestList);
                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;
            }
            for (NetworkRequestList networkRequestList : groupedNetworkRequestLists) {
            for (NetworkRequestList networkRequestList : groupedNetworkRequestLists) {
                int capability = networkRequestList.get(0).getApnTypeNetworkCapability();
                int capability = networkRequestList.get(0).getApnTypeNetworkCapability();

                for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) {
                if (retryRule.canBeMatched(capability, cause)) {
                if (retryRule.canBeMatched(capability, cause)) {
                    // Check if there is already a similar network request retry scheduled.
                    // Check if there is already a similar network request retry scheduled.
                    if (isSimilarNetworkRequestRetryScheduled(
                    if (isSimilarNetworkRequestRetryScheduled(
@@ -1147,7 +1226,6 @@ public class DataRetryManager extends Handler {
                    + "retry.");
                    + "retry.");
        }
        }
    }
    }
    }


    /**
    /**
     * Evaluate if data handover retry is needed or not. If needed, retry will be scheduled
     * Evaluate if data handover retry is needed or not. If needed, retry will be scheduled
@@ -1234,7 +1312,7 @@ public class DataRetryManager extends Handler {
            DataProfile dataProfile = dataThrottlingEntry.dataProfile;
            DataProfile dataProfile = dataThrottlingEntry.dataProfile;
            String apn = dataProfile.getApnSetting() != null
            String apn = dataProfile.getApnSetting() != null
                    ? dataProfile.getApnSetting().getApnName() : null;
                    ? dataProfile.getApnSetting().getApnName() : null;
            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false);
            onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false, true);
        }
        }


        mDataThrottlingEntries.clear();
        mDataThrottlingEntries.clear();
@@ -1393,9 +1471,10 @@ public class DataRetryManager extends Handler {
     * When this is set, {@code dataProfile} must be {@code null}.
     * When this is set, {@code dataProfile} must be {@code null}.
     * @param transport The transport that this unthrottling request is on.
     * @param transport The transport that this unthrottling request is on.
     * @param remove Whether to remove unthrottled entries from the list of entries.
     * @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,
    private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn,
            @TransportType int transport, boolean remove) {
            @TransportType int transport, boolean remove, boolean retry) {
        log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn
        log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn
                + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)
                + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)
                + ", remove=" + remove);
                + ", remove=" + remove);
@@ -1412,6 +1491,7 @@ public class DataRetryManager extends Handler {
            Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream();
            Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream();
            stream = stream.filter(entry -> entry.expirationTimeMillis > now);
            stream = stream.filter(entry -> entry.expirationTimeMillis > now);
            if (dataProfile.getApnSetting() != null) {
            if (dataProfile.getApnSetting() != null) {
                dataProfile.getApnSetting().setPermanentFailed(false);
                stream = stream
                stream = stream
                        .filter(entry -> entry.dataProfile.getApnSetting() != null)
                        .filter(entry -> entry.dataProfile.getApnSetting() != null)
                        .filter(entry -> entry.dataProfile.getApnSetting().getApnName()
                        .filter(entry -> entry.dataProfile.getApnSetting().getApnName()
@@ -1473,6 +1553,7 @@ public class DataRetryManager extends Handler {


        logl("onDataProfileUnthrottled: Removing the following throttling entries. "
        logl("onDataProfileUnthrottled: Removing the following throttling entries. "
                + dataUnthrottlingEntries);
                + dataUnthrottlingEntries);
        if (retry) {
            for (DataThrottlingEntry entry : dataUnthrottlingEntries) {
            for (DataThrottlingEntry entry : dataUnthrottlingEntries) {
                // Immediately retry after unthrottling.
                // Immediately retry after unthrottling.
                if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
                if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
@@ -1490,6 +1571,7 @@ public class DataRetryManager extends Handler {
                            .build());
                            .build());
                }
                }
            }
            }
        }
        if (remove) {
        if (remove) {
            mDataThrottlingEntries.removeAll(dataUnthrottlingEntries);
            mDataThrottlingEntries.removeAll(dataUnthrottlingEntries);
        }
        }
Loading