Loading src/java/com/android/internal/telephony/data/DataConfigManager.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -33,10 +33,15 @@ import android.telephony.SubscriptionManager; import android.util.IndentingPrintWriter; import android.util.IndentingPrintWriter; import com.android.internal.telephony.Phone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.DataRetryManager.DataRetryRule; import com.android.telephony.Rlog; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap; Loading @@ -59,6 +64,8 @@ public class DataConfigManager extends Handler { /** The network capability priority map */ /** The network capability priority map */ private final Map<Integer, Integer> mNetworkCapabilityPriorityMap = new ConcurrentHashMap<>(); private final Map<Integer, Integer> mNetworkCapabilityPriorityMap = new ConcurrentHashMap<>(); private final List<DataRetryRule> mDataRetryRules = new ArrayList<>(); private @Nullable PersistableBundle mCarrierConfig = null; private @Nullable PersistableBundle mCarrierConfig = null; private @Nullable Resources mResources = null; private @Nullable Resources mResources = null; Loading Loading @@ -132,6 +139,7 @@ public class DataConfigManager extends Handler { mPhone.getSubId()); mPhone.getSubId()); updateNetworkCapabilityPriority(); updateNetworkCapabilityPriority(); updateDataRetryRules(); log("Data config updated. Config is " + (isConfigCarrierSpecific() ? "" : "not ") log("Data config updated. Config is " + (isConfigCarrierSpecific() ? "" : "not ") + "carrier specific."); + "carrier specific."); Loading Loading @@ -180,6 +188,28 @@ public class DataConfigManager extends Handler { return 0; return 0; } } /** * Update the data retry rules from the carrier config. */ private void updateDataRetryRules() { mDataRetryRules.clear(); if (mCarrierConfig == null) return; String[] dataRetryRulesStrings = mCarrierConfig.getStringArray( CarrierConfigManager.KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY); if (dataRetryRulesStrings != null) { Arrays.stream(dataRetryRulesStrings) .map(DataRetryRule::new) .forEach(mDataRetryRules::add); } } /** * @return The data retry rules from carrier config. */ public @NonNull List<DataRetryRule> getDataRetryRules() { return Collections.unmodifiableList(mDataRetryRules); } /** /** * Registration point for subscription info ready * Registration point for subscription info ready * * Loading Loading @@ -232,6 +262,12 @@ public class DataConfigManager extends Handler { + entry.getValue() + " "); + entry.getValue() + " "); } } pw.println(); pw.println(); pw.println("Data retry rules:"); pw.increaseIndent(); for (DataRetryRule rule : mDataRetryRules) { pw.println(rule); } pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); } } Loading src/java/com/android/internal/telephony/data/DataRetryManager.java 0 → 100644 +311 −0 Original line number Original line Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkCapabilities; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.Annotation.DataFailureCause; import android.telephony.DataFailCause; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.telephony.Phone; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; /** * DataRetryManager manages data network setup retry and its configurations. */ public class DataRetryManager extends Handler { /** Event for data config updated. */ private static final int EVENT_DATA_CONFIG_UPDATED = 1; private final @NonNull Phone mPhone; private final @NonNull String mLogTag; private final @NonNull LocalLog mLocalLog = new LocalLog(128); private final @NonNull DataConfigManager mDataConfigManager; private @NonNull List<DataRetryRule> mDataRetryRuleList = new ArrayList<>(); /** * Represent a data retry rule. A rule consists a retry type (e.g. either by capabilities, * fail cause, or both), and a retry interval. */ public static final class DataRetryRule { private static final String RULE_TAG_CAPABILITIES = "capabilities"; private static final String RULE_TAG_FAIL_CAUSES = "fail_causes"; private static final String RULE_TAG_RETRY_INTERVAL = "retry_interval"; private static final String RULE_TAG_BACKOFF = "backoff"; private static final String RULE_TAG_MAXIMUM_RETRIES = "maximum_retries"; /** * The data network setup retry interval. Note that if this is {@code null}, then * {@link #getMaxRetries()} must return 0. */ private @Nullable Duration mRetryInterval = null; /** * {@code true} if this the retry interval should be backed off. For example, if the first * time retry interval is 5 seconds, next time if it fails again, the interval should be * doubled to 10 seconds. */ private boolean mBackedOffDuration = false; /** * The maximum retry times. After reaching the retry times, data retry will not be scheduled * with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, registration * state changes, etc..) can trigger the retry. */ private int mMaxRetries = 10; /** * The network capabilities NetworkCapability.NET_CAPABILITY_XXX. Each data setup must be * associated with at least one network request. If that network request contains network * capabilities specified here, then retry will happen. {@code null} means the retry rule * is not using network capabilities. */ private @Nullable int[] mNetworkCapabilities = null; /** * The fail causes. If data setup failed with certain fail causes, then retry will happen. * {@code null} means the retry rule is not using the fail causes. */ private @Nullable @DataFailureCause int[] mFailCauses = null; /** * Represent a single setup data network retry rule. * * The syntax of the retry rule: * 1. Retry based on {@link NetworkCapabilities} * "capabilities=[netCaps1|netCaps2|...], [retry_interval=x], [backoff=[true|false]], * [maximum_retries=y]" * * 2. Retry based on {@link DataFailCause} * "fail_causes=[cause1|cause2|cause3|...], [retry_interval=x], [backoff=[true|false]], * [maximum_retries=y]" * * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause} * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], * [retry_interval=x], [backoff=[true|false]], [maximum_retries=y]" * * 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 happens. * * @param ruleString The retry rule in string format. * @throws IllegalArgumentException if the string can't be parsed to a retry rule. */ public DataRetryRule(@NonNull String ruleString) { if (TextUtils.isEmpty(ruleString)) { throw new IllegalArgumentException("illegal rule " + ruleString); } ruleString = ruleString.trim().toLowerCase(Locale.ROOT); String[] expressions = ruleString.split("\\s*,\\s*"); for (String expression : expressions) { String[] tokens = expression.trim().split("\\s*=\\s*"); if (tokens.length != 2) { throw new IllegalArgumentException("illegal rule " + ruleString); } String key = tokens[0].trim(); String value = tokens[1].trim(); try { switch (key) { case RULE_TAG_CAPABILITIES: mNetworkCapabilities = Arrays.stream(value.split("\\s*\\|\\s*")) .map(String::trim) .mapToInt(DataUtils::getNetworkCapabilityFromString) .toArray(); break; case RULE_TAG_FAIL_CAUSES: mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*")) .map(String::trim) .mapToInt(Integer::valueOf) .toArray(); break; case RULE_TAG_RETRY_INTERVAL: mRetryInterval = Duration.ofMillis(Long.parseLong(value)); break; case RULE_TAG_BACKOFF: mBackedOffDuration = Boolean.parseBoolean(value); break; case RULE_TAG_MAXIMUM_RETRIES: mMaxRetries = Integer.parseInt(value); break; default: throw new IllegalArgumentException("unexpected key " + key); } } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e); } } } /** * @return The data network setup retry interval. Note that if this is {@code null}, then * {@link #getMaxRetries()} must return 0. */ public @Nullable Duration getRetryInterval() { return mRetryInterval; } /** * @return {@code true} if this the retry interval should be backed off. For example, if * the first time retry interval is 5 seconds, next time if it fails again, the interval * should be doubled to 10 seconds. */ public boolean isBackedOffDuration() { return mBackedOffDuration; } /** * @return The maximum retry times. After reaching the retry times, data retry will not be * scheduled with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, * registration state changes, etc..) can trigger the retry. */ public int getMaxRetries() { return mMaxRetries; } /** * @return The network capabilities. Each data setup must be associated with at least one * network request. If that network request contains network capabilities specified here, * then retry will happen. {@code null} means the retry rule is not using network * capabilities. */ public @Nullable int[] getNetworkCapabilities() { return mNetworkCapabilities; } /** * @return The fail causes. If data setup failed with certain fail causes, then retry will * happen. {@code null} means the retry rule is not using the fail causes. */ public @Nullable @DataFailureCause int[] getFailCauses() { return mFailCauses; } @Override public String toString() { return "[RetryRule: Network capabilities:[" + DataUtils.networkCapabilitiesToString( mNetworkCapabilities) + "], Fail causes=" + Arrays.toString(mFailCauses) + ", Retry interval=" + mRetryInterval + ", Maximum retries=" + mMaxRetries + ", Backoff=" + mBackedOffDuration + "]"; } } /** * Constructor * * @param phone The phone instance. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. */ public DataRetryManager(Phone phone, Looper looper) { super(looper); mPhone = phone; mLogTag = "DRM-" + mPhone.getPhoneId(); mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DATA_CONFIG_UPDATED: onDataConfigUpdated(); break; } } /** * Called when data config is updated. */ private void onDataConfigUpdated() { // TODO: Reset all retry related stuffs. mDataRetryRuleList = mDataConfigManager.getDataRetryRules(); } /** * Log debug messages. * @param s debug messages */ private void log(@NonNull String s) { Rlog.d(mLogTag, s); } /** * Log error messages. * @param s error messages */ private void loge(@NonNull String s) { Rlog.e(mLogTag, s); } /** * Log debug messages and also log into the local log. * @param s debug messages */ private void logl(@NonNull String s) { log(s); mLocalLog.log(s); } /** * Dump the state of DataRetryManager. * * @param fd File descriptor * @param printWriter Print writer * @param args Arguments */ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(DataRetryManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); pw.increaseIndent(); pw.println("Retry rules:"); pw.increaseIndent(); for (DataRetryRule rule : mDataRetryRuleList) { pw.println(rule); } pw.decreaseIndent(); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); pw.decreaseIndent(); } } src/java/com/android/internal/telephony/data/DataUtils.java +22 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,10 @@ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.annotation.NonNull; import android.net.NetworkCapabilities; import android.net.NetworkCapabilities; import java.util.Arrays; import java.util.Locale; import java.util.stream.Collectors; /** /** * This class contains all the utility methods used by telephony data stack. * This class contains all the utility methods used by telephony data stack. */ */ Loading @@ -30,7 +34,7 @@ public class DataUtils { * @return The network capability. * @return The network capability. */ */ public static int getNetworkCapabilityFromString(@NonNull String capabilityString) { public static int getNetworkCapabilityFromString(@NonNull String capabilityString) { switch (capabilityString) { switch (capabilityString.toUpperCase(Locale.ROOT)) { case "MMS": return NetworkCapabilities.NET_CAPABILITY_MMS; case "MMS": return NetworkCapabilities.NET_CAPABILITY_MMS; case "SUPL": return NetworkCapabilities.NET_CAPABILITY_SUPL; case "SUPL": return NetworkCapabilities.NET_CAPABILITY_SUPL; case "DUN": return NetworkCapabilities.NET_CAPABILITY_DUN; case "DUN": return NetworkCapabilities.NET_CAPABILITY_DUN; Loading @@ -50,12 +54,12 @@ public class DataUtils { } } /** /** * Convert capabilities to string. * Convert a network capability to string. * * * This is for debugging and logging purposes only. * This is for debugging and logging purposes only. * * * @param netCap Network capability * @param netCap Network capability. * @return Network capability in string format * @return Network capability in string format. */ */ public static String networkCapabilityToString(int netCap) { public static String networkCapabilityToString(int netCap) { switch (netCap) { switch (netCap) { Loading Loading @@ -98,4 +102,18 @@ public class DataUtils { return "Unknown(" + Integer.toString(netCap) + ")"; return "Unknown(" + Integer.toString(netCap) + ")"; } } } } /** * Convert network capabilities to string. * * This is for debugging and logging purposes only. * * @param netCaps Network capabilities. * @return Network capabilities in string format. */ public static String networkCapabilitiesToString(int[] netCaps) { return Arrays.stream(netCaps) .mapToObj(DataUtils::networkCapabilityToString) .collect(Collectors.joining("|")); } } } tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -86,6 +86,8 @@ import com.android.ims.ImsEcbm; import com.android.ims.ImsManager; import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.data.DataConfigManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.dataconnection.DataEnabledOverride; import com.android.internal.telephony.dataconnection.DataEnabledOverride; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DataThrottler; import com.android.internal.telephony.dataconnection.DataThrottler; Loading Loading @@ -198,6 +200,10 @@ public abstract class TelephonyTest { @Mock @Mock protected DcTracker mDcTracker; protected DcTracker mDcTracker; @Mock @Mock protected DataNetworkController mDataNetworkController; @Mock protected DataConfigManager mDataConfigManager; @Mock protected DisplayInfoController mDisplayInfoController; protected DisplayInfoController mDisplayInfoController; @Mock @Mock protected GsmCdmaCall mGsmCdmaCall; protected GsmCdmaCall mGsmCdmaCall; Loading Loading @@ -572,6 +578,7 @@ public abstract class TelephonyTest { doReturn(mTransportManager).when(mPhone).getTransportManager(); doReturn(mTransportManager).when(mPhone).getTransportManager(); doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); doReturn(mSignalStrength).when(mPhone).getSignalStrength(); doReturn(mSignalStrength).when(mPhone).getSignalStrength(); doReturn(mVoiceCallSessionStats).when(mPhone).getVoiceCallSessionStats(); doReturn(mVoiceCallSessionStats).when(mPhone).getVoiceCallSessionStats(); Loading @@ -582,6 +589,7 @@ public abstract class TelephonyTest { doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator(); doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator(); doReturn(mCellIdentity).when(mPhone).getCurrentCellIdentity(); doReturn(mCellIdentity).when(mPhone).getCurrentCellIdentity(); doReturn(mCellLocation).when(mCellIdentity).asCellLocation(); doReturn(mCellLocation).when(mCellIdentity).asCellLocation(); doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); //mUiccController //mUiccController doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(), doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(), Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -82,6 +82,7 @@ public class DataNetworkControllerTest extends TelephonyTest { @After @After public void tearDown() throws Exception { public void tearDown() throws Exception { mDataNetworkControllerTestHandler.quit(); super.tearDown(); super.tearDown(); } } Loading Loading
src/java/com/android/internal/telephony/data/DataConfigManager.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -33,10 +33,15 @@ import android.telephony.SubscriptionManager; import android.util.IndentingPrintWriter; import android.util.IndentingPrintWriter; import com.android.internal.telephony.Phone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.DataRetryManager.DataRetryRule; import com.android.telephony.Rlog; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap; Loading @@ -59,6 +64,8 @@ public class DataConfigManager extends Handler { /** The network capability priority map */ /** The network capability priority map */ private final Map<Integer, Integer> mNetworkCapabilityPriorityMap = new ConcurrentHashMap<>(); private final Map<Integer, Integer> mNetworkCapabilityPriorityMap = new ConcurrentHashMap<>(); private final List<DataRetryRule> mDataRetryRules = new ArrayList<>(); private @Nullable PersistableBundle mCarrierConfig = null; private @Nullable PersistableBundle mCarrierConfig = null; private @Nullable Resources mResources = null; private @Nullable Resources mResources = null; Loading Loading @@ -132,6 +139,7 @@ public class DataConfigManager extends Handler { mPhone.getSubId()); mPhone.getSubId()); updateNetworkCapabilityPriority(); updateNetworkCapabilityPriority(); updateDataRetryRules(); log("Data config updated. Config is " + (isConfigCarrierSpecific() ? "" : "not ") log("Data config updated. Config is " + (isConfigCarrierSpecific() ? "" : "not ") + "carrier specific."); + "carrier specific."); Loading Loading @@ -180,6 +188,28 @@ public class DataConfigManager extends Handler { return 0; return 0; } } /** * Update the data retry rules from the carrier config. */ private void updateDataRetryRules() { mDataRetryRules.clear(); if (mCarrierConfig == null) return; String[] dataRetryRulesStrings = mCarrierConfig.getStringArray( CarrierConfigManager.KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY); if (dataRetryRulesStrings != null) { Arrays.stream(dataRetryRulesStrings) .map(DataRetryRule::new) .forEach(mDataRetryRules::add); } } /** * @return The data retry rules from carrier config. */ public @NonNull List<DataRetryRule> getDataRetryRules() { return Collections.unmodifiableList(mDataRetryRules); } /** /** * Registration point for subscription info ready * Registration point for subscription info ready * * Loading Loading @@ -232,6 +262,12 @@ public class DataConfigManager extends Handler { + entry.getValue() + " "); + entry.getValue() + " "); } } pw.println(); pw.println(); pw.println("Data retry rules:"); pw.increaseIndent(); for (DataRetryRule rule : mDataRetryRules) { pw.println(rule); } pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); pw.decreaseIndent(); } } Loading
src/java/com/android/internal/telephony/data/DataRetryManager.java 0 → 100644 +311 −0 Original line number Original line Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkCapabilities; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.Annotation.DataFailureCause; import android.telephony.DataFailCause; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.telephony.Phone; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; /** * DataRetryManager manages data network setup retry and its configurations. */ public class DataRetryManager extends Handler { /** Event for data config updated. */ private static final int EVENT_DATA_CONFIG_UPDATED = 1; private final @NonNull Phone mPhone; private final @NonNull String mLogTag; private final @NonNull LocalLog mLocalLog = new LocalLog(128); private final @NonNull DataConfigManager mDataConfigManager; private @NonNull List<DataRetryRule> mDataRetryRuleList = new ArrayList<>(); /** * Represent a data retry rule. A rule consists a retry type (e.g. either by capabilities, * fail cause, or both), and a retry interval. */ public static final class DataRetryRule { private static final String RULE_TAG_CAPABILITIES = "capabilities"; private static final String RULE_TAG_FAIL_CAUSES = "fail_causes"; private static final String RULE_TAG_RETRY_INTERVAL = "retry_interval"; private static final String RULE_TAG_BACKOFF = "backoff"; private static final String RULE_TAG_MAXIMUM_RETRIES = "maximum_retries"; /** * The data network setup retry interval. Note that if this is {@code null}, then * {@link #getMaxRetries()} must return 0. */ private @Nullable Duration mRetryInterval = null; /** * {@code true} if this the retry interval should be backed off. For example, if the first * time retry interval is 5 seconds, next time if it fails again, the interval should be * doubled to 10 seconds. */ private boolean mBackedOffDuration = false; /** * The maximum retry times. After reaching the retry times, data retry will not be scheduled * with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, registration * state changes, etc..) can trigger the retry. */ private int mMaxRetries = 10; /** * The network capabilities NetworkCapability.NET_CAPABILITY_XXX. Each data setup must be * associated with at least one network request. If that network request contains network * capabilities specified here, then retry will happen. {@code null} means the retry rule * is not using network capabilities. */ private @Nullable int[] mNetworkCapabilities = null; /** * The fail causes. If data setup failed with certain fail causes, then retry will happen. * {@code null} means the retry rule is not using the fail causes. */ private @Nullable @DataFailureCause int[] mFailCauses = null; /** * Represent a single setup data network retry rule. * * The syntax of the retry rule: * 1. Retry based on {@link NetworkCapabilities} * "capabilities=[netCaps1|netCaps2|...], [retry_interval=x], [backoff=[true|false]], * [maximum_retries=y]" * * 2. Retry based on {@link DataFailCause} * "fail_causes=[cause1|cause2|cause3|...], [retry_interval=x], [backoff=[true|false]], * [maximum_retries=y]" * * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause} * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], * [retry_interval=x], [backoff=[true|false]], [maximum_retries=y]" * * 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 happens. * * @param ruleString The retry rule in string format. * @throws IllegalArgumentException if the string can't be parsed to a retry rule. */ public DataRetryRule(@NonNull String ruleString) { if (TextUtils.isEmpty(ruleString)) { throw new IllegalArgumentException("illegal rule " + ruleString); } ruleString = ruleString.trim().toLowerCase(Locale.ROOT); String[] expressions = ruleString.split("\\s*,\\s*"); for (String expression : expressions) { String[] tokens = expression.trim().split("\\s*=\\s*"); if (tokens.length != 2) { throw new IllegalArgumentException("illegal rule " + ruleString); } String key = tokens[0].trim(); String value = tokens[1].trim(); try { switch (key) { case RULE_TAG_CAPABILITIES: mNetworkCapabilities = Arrays.stream(value.split("\\s*\\|\\s*")) .map(String::trim) .mapToInt(DataUtils::getNetworkCapabilityFromString) .toArray(); break; case RULE_TAG_FAIL_CAUSES: mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*")) .map(String::trim) .mapToInt(Integer::valueOf) .toArray(); break; case RULE_TAG_RETRY_INTERVAL: mRetryInterval = Duration.ofMillis(Long.parseLong(value)); break; case RULE_TAG_BACKOFF: mBackedOffDuration = Boolean.parseBoolean(value); break; case RULE_TAG_MAXIMUM_RETRIES: mMaxRetries = Integer.parseInt(value); break; default: throw new IllegalArgumentException("unexpected key " + key); } } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e); } } } /** * @return The data network setup retry interval. Note that if this is {@code null}, then * {@link #getMaxRetries()} must return 0. */ public @Nullable Duration getRetryInterval() { return mRetryInterval; } /** * @return {@code true} if this the retry interval should be backed off. For example, if * the first time retry interval is 5 seconds, next time if it fails again, the interval * should be doubled to 10 seconds. */ public boolean isBackedOffDuration() { return mBackedOffDuration; } /** * @return The maximum retry times. After reaching the retry times, data retry will not be * scheduled with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, * registration state changes, etc..) can trigger the retry. */ public int getMaxRetries() { return mMaxRetries; } /** * @return The network capabilities. Each data setup must be associated with at least one * network request. If that network request contains network capabilities specified here, * then retry will happen. {@code null} means the retry rule is not using network * capabilities. */ public @Nullable int[] getNetworkCapabilities() { return mNetworkCapabilities; } /** * @return The fail causes. If data setup failed with certain fail causes, then retry will * happen. {@code null} means the retry rule is not using the fail causes. */ public @Nullable @DataFailureCause int[] getFailCauses() { return mFailCauses; } @Override public String toString() { return "[RetryRule: Network capabilities:[" + DataUtils.networkCapabilitiesToString( mNetworkCapabilities) + "], Fail causes=" + Arrays.toString(mFailCauses) + ", Retry interval=" + mRetryInterval + ", Maximum retries=" + mMaxRetries + ", Backoff=" + mBackedOffDuration + "]"; } } /** * Constructor * * @param phone The phone instance. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. */ public DataRetryManager(Phone phone, Looper looper) { super(looper); mPhone = phone; mLogTag = "DRM-" + mPhone.getPhoneId(); mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DATA_CONFIG_UPDATED: onDataConfigUpdated(); break; } } /** * Called when data config is updated. */ private void onDataConfigUpdated() { // TODO: Reset all retry related stuffs. mDataRetryRuleList = mDataConfigManager.getDataRetryRules(); } /** * Log debug messages. * @param s debug messages */ private void log(@NonNull String s) { Rlog.d(mLogTag, s); } /** * Log error messages. * @param s error messages */ private void loge(@NonNull String s) { Rlog.e(mLogTag, s); } /** * Log debug messages and also log into the local log. * @param s debug messages */ private void logl(@NonNull String s) { log(s); mLocalLog.log(s); } /** * Dump the state of DataRetryManager. * * @param fd File descriptor * @param printWriter Print writer * @param args Arguments */ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(DataRetryManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); pw.increaseIndent(); pw.println("Retry rules:"); pw.increaseIndent(); for (DataRetryRule rule : mDataRetryRuleList) { pw.println(rule); } pw.decreaseIndent(); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); pw.decreaseIndent(); } }
src/java/com/android/internal/telephony/data/DataUtils.java +22 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,10 @@ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.annotation.NonNull; import android.net.NetworkCapabilities; import android.net.NetworkCapabilities; import java.util.Arrays; import java.util.Locale; import java.util.stream.Collectors; /** /** * This class contains all the utility methods used by telephony data stack. * This class contains all the utility methods used by telephony data stack. */ */ Loading @@ -30,7 +34,7 @@ public class DataUtils { * @return The network capability. * @return The network capability. */ */ public static int getNetworkCapabilityFromString(@NonNull String capabilityString) { public static int getNetworkCapabilityFromString(@NonNull String capabilityString) { switch (capabilityString) { switch (capabilityString.toUpperCase(Locale.ROOT)) { case "MMS": return NetworkCapabilities.NET_CAPABILITY_MMS; case "MMS": return NetworkCapabilities.NET_CAPABILITY_MMS; case "SUPL": return NetworkCapabilities.NET_CAPABILITY_SUPL; case "SUPL": return NetworkCapabilities.NET_CAPABILITY_SUPL; case "DUN": return NetworkCapabilities.NET_CAPABILITY_DUN; case "DUN": return NetworkCapabilities.NET_CAPABILITY_DUN; Loading @@ -50,12 +54,12 @@ public class DataUtils { } } /** /** * Convert capabilities to string. * Convert a network capability to string. * * * This is for debugging and logging purposes only. * This is for debugging and logging purposes only. * * * @param netCap Network capability * @param netCap Network capability. * @return Network capability in string format * @return Network capability in string format. */ */ public static String networkCapabilityToString(int netCap) { public static String networkCapabilityToString(int netCap) { switch (netCap) { switch (netCap) { Loading Loading @@ -98,4 +102,18 @@ public class DataUtils { return "Unknown(" + Integer.toString(netCap) + ")"; return "Unknown(" + Integer.toString(netCap) + ")"; } } } } /** * Convert network capabilities to string. * * This is for debugging and logging purposes only. * * @param netCaps Network capabilities. * @return Network capabilities in string format. */ public static String networkCapabilitiesToString(int[] netCaps) { return Arrays.stream(netCaps) .mapToObj(DataUtils::networkCapabilityToString) .collect(Collectors.joining("|")); } } }
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -86,6 +86,8 @@ import com.android.ims.ImsEcbm; import com.android.ims.ImsManager; import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.data.DataConfigManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.dataconnection.DataEnabledOverride; import com.android.internal.telephony.dataconnection.DataEnabledOverride; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DataThrottler; import com.android.internal.telephony.dataconnection.DataThrottler; Loading Loading @@ -198,6 +200,10 @@ public abstract class TelephonyTest { @Mock @Mock protected DcTracker mDcTracker; protected DcTracker mDcTracker; @Mock @Mock protected DataNetworkController mDataNetworkController; @Mock protected DataConfigManager mDataConfigManager; @Mock protected DisplayInfoController mDisplayInfoController; protected DisplayInfoController mDisplayInfoController; @Mock @Mock protected GsmCdmaCall mGsmCdmaCall; protected GsmCdmaCall mGsmCdmaCall; Loading Loading @@ -572,6 +578,7 @@ public abstract class TelephonyTest { doReturn(mTransportManager).when(mPhone).getTransportManager(); doReturn(mTransportManager).when(mPhone).getTransportManager(); doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); doReturn(mSignalStrength).when(mPhone).getSignalStrength(); doReturn(mSignalStrength).when(mPhone).getSignalStrength(); doReturn(mVoiceCallSessionStats).when(mPhone).getVoiceCallSessionStats(); doReturn(mVoiceCallSessionStats).when(mPhone).getVoiceCallSessionStats(); Loading @@ -582,6 +589,7 @@ public abstract class TelephonyTest { doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator(); doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator(); doReturn(mCellIdentity).when(mPhone).getCurrentCellIdentity(); doReturn(mCellIdentity).when(mPhone).getCurrentCellIdentity(); doReturn(mCellLocation).when(mCellIdentity).asCellLocation(); doReturn(mCellLocation).when(mCellIdentity).asCellLocation(); doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); //mUiccController //mUiccController doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(), doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(), Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -82,6 +82,7 @@ public class DataNetworkControllerTest extends TelephonyTest { @After @After public void tearDown() throws Exception { public void tearDown() throws Exception { mDataNetworkControllerTestHandler.quit(); super.tearDown(); super.tearDown(); } } Loading