Loading src/java/com/android/internal/telephony/data/DataEvaluation.java +45 −21 Original line number Diff line number Diff line Loading @@ -195,50 +195,74 @@ public class DataEvaluation { @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. */ Loading src/java/com/android/internal/telephony/data/DataNetwork.java +1 −1 Original line number Diff line number Diff line Loading @@ -3190,7 +3190,7 @@ public class DataNetwork extends StateMachine { && !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 Loading src/java/com/android/internal/telephony/data/DataNetworkController.java +19 −2 Original line number Diff line number Diff line Loading @@ -551,6 +551,15 @@ public class DataNetworkController extends Handler { */ 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() {} Loading Loading @@ -1426,7 +1435,7 @@ public class DataNetworkController extends Handler { 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; Loading Loading @@ -1576,7 +1585,10 @@ public class DataNetworkController extends Handler { networkType = mServiceState.getVoiceNetworkType(); } 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) { evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); } else if (reason == DataEvaluationReason.NEW_REQUEST Loading Loading @@ -2603,6 +2615,11 @@ public class DataNetworkController extends Handler { */ 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) { Loading src/java/com/android/internal/telephony/data/DataProfileManager.java +27 −4 Original line number Diff line number Diff line Loading @@ -621,14 +621,18 @@ public class DataProfileManager extends Handler { * * @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(); Loading Loading @@ -687,10 +691,13 @@ public class DataProfileManager extends Handler { * * @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."); Loading Loading @@ -733,6 +740,7 @@ public class DataProfileManager extends Handler { && (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=" Loading @@ -740,6 +748,15 @@ public class DataProfileManager extends Handler { 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(); } Loading Loading @@ -772,7 +789,7 @@ public class DataProfileManager extends Handler { new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .build(), mPhone); return getDataProfileForNetworkRequest(networkRequest, networkType) != null; return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null; } /** Loading Loading @@ -1095,6 +1112,12 @@ public class DataProfileManager extends Handler { 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(); Loading src/java/com/android/internal/telephony/data/DataRetryManager.java +170 −88 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ import java.io.FileDescriptor; 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; Loading Loading @@ -315,10 +314,6 @@ public class DataRetryManager extends Handler { } } if (mMaxRetries == 0) { mRetryIntervalsMillis = Collections.emptyList(); } if (mMaxRetries < 0) { throw new IllegalArgumentException("Max retries should not be less than 0. " + "mMaxRetries=" + mMaxRetries); Loading Loading @@ -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: * 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 * Loading @@ -410,8 +411,23 @@ public class DataRetryManager extends Handler { } 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); } } Loading @@ -433,6 +449,13 @@ public class DataRetryManager extends Handler { 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. * Loading Loading @@ -949,10 +972,27 @@ public class DataRetryManager extends Handler { }); 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); Loading Loading @@ -1001,7 +1041,7 @@ public class DataRetryManager extends Handler { } 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); Loading Loading @@ -1034,6 +1074,21 @@ public class DataRetryManager extends Handler { + ", 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 * automatically after evaluation. Loading Loading @@ -1072,6 +1127,7 @@ public class DataRetryManager extends Handler { // 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<>() Loading @@ -1085,23 +1141,46 @@ public class DataRetryManager extends Handler { 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); // Support the legacy permanent failure configuration if (DataFailCause.isPermanentFailure(mPhone.getContext(), cause, mPhone.getSubId())) { log("Stopped timer-based retry. cause=" + DataFailCause.toString(cause)); return; } // 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; } 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( Loading Loading @@ -1147,7 +1226,6 @@ public class DataRetryManager extends Handler { + "retry."); } } } /** * Evaluate if data handover retry is needed or not. If needed, retry will be scheduled Loading Loading @@ -1234,7 +1312,7 @@ public class DataRetryManager extends Handler { 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(); Loading Loading @@ -1393,9 +1471,10 @@ public class DataRetryManager extends Handler { * 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, @TransportType int transport, boolean remove) { @TransportType int transport, boolean remove, boolean retry) { log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) + ", remove=" + remove); Loading @@ -1412,6 +1491,7 @@ public class DataRetryManager extends Handler { 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() Loading Loading @@ -1473,6 +1553,7 @@ public class DataRetryManager extends Handler { logl("onDataProfileUnthrottled: Removing the following throttling entries. " + dataUnthrottlingEntries); if (retry) { for (DataThrottlingEntry entry : dataUnthrottlingEntries) { // Immediately retry after unthrottling. if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { Loading @@ -1490,6 +1571,7 @@ public class DataRetryManager extends Handler { .build()); } } } if (remove) { mDataThrottlingEntries.removeAll(dataUnthrottlingEntries); } Loading Loading
src/java/com/android/internal/telephony/data/DataEvaluation.java +45 −21 Original line number Diff line number Diff line Loading @@ -195,50 +195,74 @@ public class DataEvaluation { @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. */ Loading
src/java/com/android/internal/telephony/data/DataNetwork.java +1 −1 Original line number Diff line number Diff line Loading @@ -3190,7 +3190,7 @@ public class DataNetwork extends StateMachine { && !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 Loading
src/java/com/android/internal/telephony/data/DataNetworkController.java +19 −2 Original line number Diff line number Diff line Loading @@ -551,6 +551,15 @@ public class DataNetworkController extends Handler { */ 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() {} Loading Loading @@ -1426,7 +1435,7 @@ public class DataNetworkController extends Handler { 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; Loading Loading @@ -1576,7 +1585,10 @@ public class DataNetworkController extends Handler { networkType = mServiceState.getVoiceNetworkType(); } 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) { evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); } else if (reason == DataEvaluationReason.NEW_REQUEST Loading Loading @@ -2603,6 +2615,11 @@ public class DataNetworkController extends Handler { */ 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) { Loading
src/java/com/android/internal/telephony/data/DataProfileManager.java +27 −4 Original line number Diff line number Diff line Loading @@ -621,14 +621,18 @@ public class DataProfileManager extends Handler { * * @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(); Loading Loading @@ -687,10 +691,13 @@ public class DataProfileManager extends Handler { * * @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."); Loading Loading @@ -733,6 +740,7 @@ public class DataProfileManager extends Handler { && (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=" Loading @@ -740,6 +748,15 @@ public class DataProfileManager extends Handler { 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(); } Loading Loading @@ -772,7 +789,7 @@ public class DataProfileManager extends Handler { new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .build(), mPhone); return getDataProfileForNetworkRequest(networkRequest, networkType) != null; return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null; } /** Loading Loading @@ -1095,6 +1112,12 @@ public class DataProfileManager extends Handler { 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(); Loading
src/java/com/android/internal/telephony/data/DataRetryManager.java +170 −88 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ import java.io.FileDescriptor; 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; Loading Loading @@ -315,10 +314,6 @@ public class DataRetryManager extends Handler { } } if (mMaxRetries == 0) { mRetryIntervalsMillis = Collections.emptyList(); } if (mMaxRetries < 0) { throw new IllegalArgumentException("Max retries should not be less than 0. " + "mMaxRetries=" + mMaxRetries); Loading Loading @@ -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: * 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 * Loading @@ -410,8 +411,23 @@ public class DataRetryManager extends Handler { } 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); } } Loading @@ -433,6 +449,13 @@ public class DataRetryManager extends Handler { 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. * Loading Loading @@ -949,10 +972,27 @@ public class DataRetryManager extends Handler { }); 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); Loading Loading @@ -1001,7 +1041,7 @@ public class DataRetryManager extends Handler { } 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); Loading Loading @@ -1034,6 +1074,21 @@ public class DataRetryManager extends Handler { + ", 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 * automatically after evaluation. Loading Loading @@ -1072,6 +1127,7 @@ public class DataRetryManager extends Handler { // 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<>() Loading @@ -1085,23 +1141,46 @@ public class DataRetryManager extends Handler { 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); // Support the legacy permanent failure configuration if (DataFailCause.isPermanentFailure(mPhone.getContext(), cause, mPhone.getSubId())) { log("Stopped timer-based retry. cause=" + DataFailCause.toString(cause)); return; } // 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; } 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( Loading Loading @@ -1147,7 +1226,6 @@ public class DataRetryManager extends Handler { + "retry."); } } } /** * Evaluate if data handover retry is needed or not. If needed, retry will be scheduled Loading Loading @@ -1234,7 +1312,7 @@ public class DataRetryManager extends Handler { 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(); Loading Loading @@ -1393,9 +1471,10 @@ public class DataRetryManager extends Handler { * 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, @TransportType int transport, boolean remove) { @TransportType int transport, boolean remove, boolean retry) { log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) + ", remove=" + remove); Loading @@ -1412,6 +1491,7 @@ public class DataRetryManager extends Handler { 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() Loading Loading @@ -1473,6 +1553,7 @@ public class DataRetryManager extends Handler { logl("onDataProfileUnthrottled: Removing the following throttling entries. " + dataUnthrottlingEntries); if (retry) { for (DataThrottlingEntry entry : dataUnthrottlingEntries) { // Immediately retry after unthrottling. if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { Loading @@ -1490,6 +1571,7 @@ public class DataRetryManager extends Handler { .build()); } } } if (remove) { mDataThrottlingEntries.removeAll(dataUnthrottlingEntries); } Loading