Loading src/java/com/android/internal/telephony/data/DataNetworkController.java +39 −12 Original line number Original line Diff line number Diff line Loading @@ -579,6 +579,8 @@ public class DataNetworkController extends Handler { private static final String RULE_TAG_TYPE = "type"; private static final String RULE_TAG_TYPE = "type"; private static final String RULE_TAG_CAPABILITIES = "capabilities"; private static final String RULE_TAG_ROAMING = "roaming"; private static final String RULE_TAG_ROAMING = "roaming"; /** Handover rule type. */ /** Handover rule type. */ Loading @@ -590,6 +592,12 @@ public class DataNetworkController extends Handler { /** The applicable target access networks for handover. */ /** The applicable target access networks for handover. */ public final @NonNull @RadioAccessNetworkType Set<Integer> targetAccessNetworks; public final @NonNull @RadioAccessNetworkType Set<Integer> targetAccessNetworks; /** * The network capabilities to any of which this handover rule applies. * If is empty, then capability is ignored as a rule matcher. */ public final @NonNull @NetCapability Set<Integer> networkCapabilities; /** {@code true} indicates this policy is only applicable when the device is roaming. */ /** {@code true} indicates this policy is only applicable when the device is roaming. */ public final boolean isOnlyForRoaming; public final boolean isOnlyForRoaming; Loading @@ -605,7 +613,7 @@ public class DataNetworkController extends Handler { throw new IllegalArgumentException("illegal rule " + ruleString); throw new IllegalArgumentException("illegal rule " + ruleString); } } Set<Integer> source = null, target = null; Set<Integer> source = null, target = null, capabilities = Collections.emptySet(); int type = 0; int type = 0; boolean roaming = false; boolean roaming = false; Loading Loading @@ -642,6 +650,9 @@ public class DataNetworkController extends Handler { throw new IllegalArgumentException("unexpected rule type " + value); throw new IllegalArgumentException("unexpected rule type " + value); } } break; break; case RULE_TAG_CAPABILITIES: capabilities = DataUtils.getNetworkCapabilitiesFromString(value); break; case RULE_TAG_ROAMING: case RULE_TAG_ROAMING: roaming = Boolean.parseBoolean(value); roaming = Boolean.parseBoolean(value); break; break; Loading @@ -655,7 +666,7 @@ public class DataNetworkController extends Handler { } } } } if (source == null || target == null) { if (source == null || target == null || source.isEmpty() || target.isEmpty()) { throw new IllegalArgumentException("Need to specify both source and target. " throw new IllegalArgumentException("Need to specify both source and target. " + "\"" + ruleString + "\""); + "\"" + ruleString + "\""); } } Loading @@ -675,6 +686,11 @@ public class DataNetworkController extends Handler { + "\"" + ruleString + "\""); + "\"" + ruleString + "\""); } } if (capabilities != null && capabilities.contains(-1)) { throw new IllegalArgumentException("Network capabilities contains unknown. " + "\"" + ruleString + "\""); } if (!source.contains(AccessNetworkType.IWLAN) if (!source.contains(AccessNetworkType.IWLAN) && !target.contains(AccessNetworkType.IWLAN)) { && !target.contains(AccessNetworkType.IWLAN)) { throw new IllegalArgumentException("IWLAN must be specified in either source or " throw new IllegalArgumentException("IWLAN must be specified in either source or " Loading @@ -684,6 +700,7 @@ public class DataNetworkController extends Handler { sourceAccessNetworks = source; sourceAccessNetworks = source; targetAccessNetworks = target; targetAccessNetworks = target; this.type = type; this.type = type; networkCapabilities = capabilities; isOnlyForRoaming = roaming; isOnlyForRoaming = roaming; } } Loading @@ -693,7 +710,9 @@ public class DataNetworkController extends Handler { : "disallowed") + ", source=" + sourceAccessNetworks.stream() : "disallowed") + ", source=" + sourceAccessNetworks.stream() .map(AccessNetworkType::toString).collect(Collectors.joining("|")) .map(AccessNetworkType::toString).collect(Collectors.joining("|")) + ", target=" + targetAccessNetworks.stream().map(AccessNetworkType::toString) + ", target=" + targetAccessNetworks.stream().map(AccessNetworkType::toString) .collect(Collectors.joining("|")) + ", isRoaming=" + isOnlyForRoaming + "]"; .collect(Collectors.joining("|")) + ", isRoaming=" + isOnlyForRoaming + ", capabilities=" + DataUtils.networkCapabilitiesToString(networkCapabilities) + "]"; } } } } Loading Loading @@ -1618,10 +1637,12 @@ public class DataNetworkController extends Handler { getDataNetworkType(dataNetwork.getTransport())); getDataNetworkType(dataNetwork.getTransport())); int targetAccessNetwork = DataUtils.networkTypeToAccessNetworkType( int targetAccessNetwork = DataUtils.networkTypeToAccessNetworkType( getDataNetworkType(DataUtils.getTargetTransport(dataNetwork.getTransport()))); getDataNetworkType(DataUtils.getTargetTransport(dataNetwork.getTransport()))); NetworkCapabilities capabilities = dataNetwork.getNetworkCapabilities(); log("evaluateDataNetworkHandover: " log("evaluateDataNetworkHandover: " + "source=" + AccessNetworkType.toString(sourceAccessNetwork) + "source=" + AccessNetworkType.toString(sourceAccessNetwork) + ", target=" + AccessNetworkType.toString(targetAccessNetwork) + ", target=" + AccessNetworkType.toString(targetAccessNetwork) + ", ServiceState=" + mServiceState); + ", ServiceState=" + mServiceState + ", capabilities=" + capabilities); // Matching the rules by the configured order. Bail out if find first matching rule. // Matching the rules by the configured order. Bail out if find first matching rule. for (HandoverRule rule : handoverRules) { for (HandoverRule rule : handoverRules) { Loading @@ -1630,6 +1651,11 @@ public class DataNetworkController extends Handler { if (rule.sourceAccessNetworks.contains(sourceAccessNetwork) if (rule.sourceAccessNetworks.contains(sourceAccessNetwork) && rule.targetAccessNetworks.contains(targetAccessNetwork)) { && rule.targetAccessNetworks.contains(targetAccessNetwork)) { // if no capability rule specified, data network capability is considered matched. // otherwise, any capabilities overlap is also considered matched. if (rule.networkCapabilities.isEmpty() || rule.networkCapabilities.stream() .anyMatch(capabilities::hasCapability)) { log("evaluateDataNetworkHandover: Matched " + rule); log("evaluateDataNetworkHandover: Matched " + rule); if (rule.type == HandoverRule.RULE_TYPE_DISALLOWED) { if (rule.type == HandoverRule.RULE_TYPE_DISALLOWED) { dataEvaluation.addDataDisallowedReason( dataEvaluation.addDataDisallowedReason( Loading @@ -1641,6 +1667,7 @@ public class DataNetworkController extends Handler { return dataEvaluation; return dataEvaluation; } } } } } log("evaluateDataNetworkHandover: Did not find matching rule. " + dataEvaluation); log("evaluateDataNetworkHandover: Did not find matching rule. " + dataEvaluation); // Allow handover anyway if no rule is found. // Allow handover anyway if no rule is found. Loading src/java/com/android/internal/telephony/data/DataRetryManager.java +4 −6 Original line number Original line Diff line number Diff line Loading @@ -402,16 +402,14 @@ 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)) { if (key.equals(RULE_TAG_CAPABILITIES)) { mNetworkCapabilities = Arrays.stream(value.split("\\s*\\|\\s*")) mNetworkCapabilities = DataUtils.getNetworkCapabilitiesFromString(value); .map(String::trim) .map(DataUtils::getNetworkCapabilityFromString) .collect(Collectors.toSet()); } } } } if (mNetworkCapabilities.size() == 0 && mFailCauses.size() == 0) { if (mFailCauses.isEmpty() && (mNetworkCapabilities.isEmpty() || mNetworkCapabilities.contains(-1))) { throw new IllegalArgumentException("illegal rule " + ruleString throw new IllegalArgumentException("illegal rule " + ruleString + ". Should have either network capabilities or fail causes."); + ". Should have either valid network capabilities or fail causes."); } } } } Loading src/java/com/android/internal/telephony/data/DataUtils.java +23 −1 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ import com.android.internal.telephony.data.DataNetworkController.NetworkRequestL import java.text.SimpleDateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Comparator; import java.util.List; import java.util.List; import java.util.Locale; import java.util.Locale; Loading Loading @@ -89,6 +91,26 @@ public class DataUtils { } } } } /** * Get Set of network capabilities from string joined by {@code |}, space is ignored. * If input string contains unknown capability or malformatted(e.g. empty string), -1 is * included in the returned set. * * @param capabilitiesString capability strings joined by {@code |} * @return Set of capabilities */ public static @NetCapability Set<Integer> getNetworkCapabilitiesFromString( @NonNull String capabilitiesString) { // e.g. "IMS|" is not allowed if (!capabilitiesString.matches("(\\s*[a-zA-Z]+\\s*)(\\|\\s*[a-zA-Z]+\\s*)*")) { return Collections.singleton(-1); } return Arrays.stream(capabilitiesString.split("\\s*\\|\\s*")) .map(String::trim) .map(DataUtils::getNetworkCapabilityFromString) .collect(Collectors.toSet()); } /** /** * Convert a network capability to string. * Convert a network capability to string. * * Loading Loading @@ -153,7 +175,7 @@ public class DataUtils { * @return Network capabilities in string format. * @return Network capabilities in string format. */ */ public static @NonNull String networkCapabilitiesToString( public static @NonNull String networkCapabilitiesToString( @NetCapability @Nullable List<Integer> netCaps) { @NetCapability @Nullable Collection<Integer> netCaps) { if (netCaps == null || netCaps.isEmpty()) return ""; if (netCaps == null || netCaps.isEmpty()) return ""; return "[" + netCaps.stream() return "[" + netCaps.stream() .map(DataUtils::networkCapabilityToString) .map(DataUtils::networkCapabilityToString) Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +35 −3 Original line number Original line Diff line number Diff line Loading @@ -1112,6 +1112,7 @@ public class DataNetworkControllerTest extends TelephonyTest { AccessNetworkType.IWLAN); AccessNetworkType.IWLAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_ALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_ALLOWED); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.networkCapabilities).isEmpty(); handoverRule = new HandoverRule("source= NGRAN| IWLAN, " handoverRule = new HandoverRule("source= NGRAN| IWLAN, " + "target = EUTRAN, type = disallowed "); + "target = EUTRAN, type = disallowed "); Loading @@ -1120,12 +1121,16 @@ public class DataNetworkControllerTest extends TelephonyTest { assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.networkCapabilities).isEmpty(); handoverRule = new HandoverRule("source= IWLAN, " handoverRule = new HandoverRule("source= IWLAN, " + "target = EUTRAN, type = disallowed, roaming = true"); + "target = EUTRAN, type = disallowed, roaming = true," + " capabilities = IMS | EIMS "); assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.IWLAN); assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.IWLAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.networkCapabilities).containsExactly( NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_EIMS); assertThat(handoverRule.isOnlyForRoaming).isTrue(); assertThat(handoverRule.isOnlyForRoaming).isTrue(); assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class, Loading @@ -1145,6 +1150,19 @@ public class DataNetworkControllerTest extends TelephonyTest { assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=IWLAN, target=WTFRAN, type=allowed")); () -> new HandoverRule("source=IWLAN, target=WTFRAN, type=allowed")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=IWLAN, target=|, type=allowed")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=|")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, " + "capabilities=wtf")); } } @Test @Test Loading Loading @@ -1364,7 +1382,8 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test @Test public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{"source=EUTRAN, target=IWLAN, type=disallowed"}); new String[]{"source=EUTRAN, target=IWLAN, type=disallowed, capabilities=MMS|IMS", "source=IWLAN, target=EUTRAN, type=disallowed, capabilities=MMS"}); // Force data config manager to reload the carrier config. // Force data config manager to reload the carrier config. mDataNetworkControllerUT.getDataConfigManager().obtainMessage( mDataNetworkControllerUT.getDataConfigManager().obtainMessage( 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); Loading @@ -1391,6 +1410,19 @@ public class DataNetworkControllerTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); assertThat(dataNetworkList.get(0).getTransport()) assertThat(dataNetworkList.get(0).getTransport()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); // test IWLAN -> EUTRAN no need to tear down because the disallowed rule only applies to MMS doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); // After this, IMS data network should be disconnected, and DNC should attempt to // establish a new one on IWLAN processAllMessages(); DataNetwork dataNetwork = getDataNetworks().get(0); // Verify that IWWAN handover succeeded. assertThat(dataNetwork.getTransport()).isEqualTo( AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } } @Test @Test Loading tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -93,4 +93,32 @@ public class DataUtilsTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); } } @Test public void testGetNetworkCapabilitiesFromString() { String normal = " MMS "; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS); String normal2 = "MMS|IMS"; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal2)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_IMS); String normal3 = " MMS |IMS "; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal3)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_IMS); String containsUnknown = "MMS |IMS | what"; assertThat(DataUtils.getNetworkCapabilitiesFromString(containsUnknown) .contains(-1)).isTrue(); String malFormatted = ""; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted).contains(-1)).isTrue(); String malFormatted2 = " "; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted2).contains(-1)).isTrue(); String malFormatted3 = "MMS |IMS |"; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted3).contains(-1)).isTrue(); String composedDelim = " | ||"; assertThat(DataUtils.getNetworkCapabilitiesFromString(composedDelim).contains(-1)).isTrue(); String malFormatted4 = "mms||ims"; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted4).contains(-1)).isTrue(); } } } Loading
src/java/com/android/internal/telephony/data/DataNetworkController.java +39 −12 Original line number Original line Diff line number Diff line Loading @@ -579,6 +579,8 @@ public class DataNetworkController extends Handler { private static final String RULE_TAG_TYPE = "type"; private static final String RULE_TAG_TYPE = "type"; private static final String RULE_TAG_CAPABILITIES = "capabilities"; private static final String RULE_TAG_ROAMING = "roaming"; private static final String RULE_TAG_ROAMING = "roaming"; /** Handover rule type. */ /** Handover rule type. */ Loading @@ -590,6 +592,12 @@ public class DataNetworkController extends Handler { /** The applicable target access networks for handover. */ /** The applicable target access networks for handover. */ public final @NonNull @RadioAccessNetworkType Set<Integer> targetAccessNetworks; public final @NonNull @RadioAccessNetworkType Set<Integer> targetAccessNetworks; /** * The network capabilities to any of which this handover rule applies. * If is empty, then capability is ignored as a rule matcher. */ public final @NonNull @NetCapability Set<Integer> networkCapabilities; /** {@code true} indicates this policy is only applicable when the device is roaming. */ /** {@code true} indicates this policy is only applicable when the device is roaming. */ public final boolean isOnlyForRoaming; public final boolean isOnlyForRoaming; Loading @@ -605,7 +613,7 @@ public class DataNetworkController extends Handler { throw new IllegalArgumentException("illegal rule " + ruleString); throw new IllegalArgumentException("illegal rule " + ruleString); } } Set<Integer> source = null, target = null; Set<Integer> source = null, target = null, capabilities = Collections.emptySet(); int type = 0; int type = 0; boolean roaming = false; boolean roaming = false; Loading Loading @@ -642,6 +650,9 @@ public class DataNetworkController extends Handler { throw new IllegalArgumentException("unexpected rule type " + value); throw new IllegalArgumentException("unexpected rule type " + value); } } break; break; case RULE_TAG_CAPABILITIES: capabilities = DataUtils.getNetworkCapabilitiesFromString(value); break; case RULE_TAG_ROAMING: case RULE_TAG_ROAMING: roaming = Boolean.parseBoolean(value); roaming = Boolean.parseBoolean(value); break; break; Loading @@ -655,7 +666,7 @@ public class DataNetworkController extends Handler { } } } } if (source == null || target == null) { if (source == null || target == null || source.isEmpty() || target.isEmpty()) { throw new IllegalArgumentException("Need to specify both source and target. " throw new IllegalArgumentException("Need to specify both source and target. " + "\"" + ruleString + "\""); + "\"" + ruleString + "\""); } } Loading @@ -675,6 +686,11 @@ public class DataNetworkController extends Handler { + "\"" + ruleString + "\""); + "\"" + ruleString + "\""); } } if (capabilities != null && capabilities.contains(-1)) { throw new IllegalArgumentException("Network capabilities contains unknown. " + "\"" + ruleString + "\""); } if (!source.contains(AccessNetworkType.IWLAN) if (!source.contains(AccessNetworkType.IWLAN) && !target.contains(AccessNetworkType.IWLAN)) { && !target.contains(AccessNetworkType.IWLAN)) { throw new IllegalArgumentException("IWLAN must be specified in either source or " throw new IllegalArgumentException("IWLAN must be specified in either source or " Loading @@ -684,6 +700,7 @@ public class DataNetworkController extends Handler { sourceAccessNetworks = source; sourceAccessNetworks = source; targetAccessNetworks = target; targetAccessNetworks = target; this.type = type; this.type = type; networkCapabilities = capabilities; isOnlyForRoaming = roaming; isOnlyForRoaming = roaming; } } Loading @@ -693,7 +710,9 @@ public class DataNetworkController extends Handler { : "disallowed") + ", source=" + sourceAccessNetworks.stream() : "disallowed") + ", source=" + sourceAccessNetworks.stream() .map(AccessNetworkType::toString).collect(Collectors.joining("|")) .map(AccessNetworkType::toString).collect(Collectors.joining("|")) + ", target=" + targetAccessNetworks.stream().map(AccessNetworkType::toString) + ", target=" + targetAccessNetworks.stream().map(AccessNetworkType::toString) .collect(Collectors.joining("|")) + ", isRoaming=" + isOnlyForRoaming + "]"; .collect(Collectors.joining("|")) + ", isRoaming=" + isOnlyForRoaming + ", capabilities=" + DataUtils.networkCapabilitiesToString(networkCapabilities) + "]"; } } } } Loading Loading @@ -1618,10 +1637,12 @@ public class DataNetworkController extends Handler { getDataNetworkType(dataNetwork.getTransport())); getDataNetworkType(dataNetwork.getTransport())); int targetAccessNetwork = DataUtils.networkTypeToAccessNetworkType( int targetAccessNetwork = DataUtils.networkTypeToAccessNetworkType( getDataNetworkType(DataUtils.getTargetTransport(dataNetwork.getTransport()))); getDataNetworkType(DataUtils.getTargetTransport(dataNetwork.getTransport()))); NetworkCapabilities capabilities = dataNetwork.getNetworkCapabilities(); log("evaluateDataNetworkHandover: " log("evaluateDataNetworkHandover: " + "source=" + AccessNetworkType.toString(sourceAccessNetwork) + "source=" + AccessNetworkType.toString(sourceAccessNetwork) + ", target=" + AccessNetworkType.toString(targetAccessNetwork) + ", target=" + AccessNetworkType.toString(targetAccessNetwork) + ", ServiceState=" + mServiceState); + ", ServiceState=" + mServiceState + ", capabilities=" + capabilities); // Matching the rules by the configured order. Bail out if find first matching rule. // Matching the rules by the configured order. Bail out if find first matching rule. for (HandoverRule rule : handoverRules) { for (HandoverRule rule : handoverRules) { Loading @@ -1630,6 +1651,11 @@ public class DataNetworkController extends Handler { if (rule.sourceAccessNetworks.contains(sourceAccessNetwork) if (rule.sourceAccessNetworks.contains(sourceAccessNetwork) && rule.targetAccessNetworks.contains(targetAccessNetwork)) { && rule.targetAccessNetworks.contains(targetAccessNetwork)) { // if no capability rule specified, data network capability is considered matched. // otherwise, any capabilities overlap is also considered matched. if (rule.networkCapabilities.isEmpty() || rule.networkCapabilities.stream() .anyMatch(capabilities::hasCapability)) { log("evaluateDataNetworkHandover: Matched " + rule); log("evaluateDataNetworkHandover: Matched " + rule); if (rule.type == HandoverRule.RULE_TYPE_DISALLOWED) { if (rule.type == HandoverRule.RULE_TYPE_DISALLOWED) { dataEvaluation.addDataDisallowedReason( dataEvaluation.addDataDisallowedReason( Loading @@ -1641,6 +1667,7 @@ public class DataNetworkController extends Handler { return dataEvaluation; return dataEvaluation; } } } } } log("evaluateDataNetworkHandover: Did not find matching rule. " + dataEvaluation); log("evaluateDataNetworkHandover: Did not find matching rule. " + dataEvaluation); // Allow handover anyway if no rule is found. // Allow handover anyway if no rule is found. Loading
src/java/com/android/internal/telephony/data/DataRetryManager.java +4 −6 Original line number Original line Diff line number Diff line Loading @@ -402,16 +402,14 @@ 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)) { if (key.equals(RULE_TAG_CAPABILITIES)) { mNetworkCapabilities = Arrays.stream(value.split("\\s*\\|\\s*")) mNetworkCapabilities = DataUtils.getNetworkCapabilitiesFromString(value); .map(String::trim) .map(DataUtils::getNetworkCapabilityFromString) .collect(Collectors.toSet()); } } } } if (mNetworkCapabilities.size() == 0 && mFailCauses.size() == 0) { if (mFailCauses.isEmpty() && (mNetworkCapabilities.isEmpty() || mNetworkCapabilities.contains(-1))) { throw new IllegalArgumentException("illegal rule " + ruleString throw new IllegalArgumentException("illegal rule " + ruleString + ". Should have either network capabilities or fail causes."); + ". Should have either valid network capabilities or fail causes."); } } } } Loading
src/java/com/android/internal/telephony/data/DataUtils.java +23 −1 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ import com.android.internal.telephony.data.DataNetworkController.NetworkRequestL import java.text.SimpleDateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Comparator; import java.util.List; import java.util.List; import java.util.Locale; import java.util.Locale; Loading Loading @@ -89,6 +91,26 @@ public class DataUtils { } } } } /** * Get Set of network capabilities from string joined by {@code |}, space is ignored. * If input string contains unknown capability or malformatted(e.g. empty string), -1 is * included in the returned set. * * @param capabilitiesString capability strings joined by {@code |} * @return Set of capabilities */ public static @NetCapability Set<Integer> getNetworkCapabilitiesFromString( @NonNull String capabilitiesString) { // e.g. "IMS|" is not allowed if (!capabilitiesString.matches("(\\s*[a-zA-Z]+\\s*)(\\|\\s*[a-zA-Z]+\\s*)*")) { return Collections.singleton(-1); } return Arrays.stream(capabilitiesString.split("\\s*\\|\\s*")) .map(String::trim) .map(DataUtils::getNetworkCapabilityFromString) .collect(Collectors.toSet()); } /** /** * Convert a network capability to string. * Convert a network capability to string. * * Loading Loading @@ -153,7 +175,7 @@ public class DataUtils { * @return Network capabilities in string format. * @return Network capabilities in string format. */ */ public static @NonNull String networkCapabilitiesToString( public static @NonNull String networkCapabilitiesToString( @NetCapability @Nullable List<Integer> netCaps) { @NetCapability @Nullable Collection<Integer> netCaps) { if (netCaps == null || netCaps.isEmpty()) return ""; if (netCaps == null || netCaps.isEmpty()) return ""; return "[" + netCaps.stream() return "[" + netCaps.stream() .map(DataUtils::networkCapabilityToString) .map(DataUtils::networkCapabilityToString) Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +35 −3 Original line number Original line Diff line number Diff line Loading @@ -1112,6 +1112,7 @@ public class DataNetworkControllerTest extends TelephonyTest { AccessNetworkType.IWLAN); AccessNetworkType.IWLAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_ALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_ALLOWED); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.networkCapabilities).isEmpty(); handoverRule = new HandoverRule("source= NGRAN| IWLAN, " handoverRule = new HandoverRule("source= NGRAN| IWLAN, " + "target = EUTRAN, type = disallowed "); + "target = EUTRAN, type = disallowed "); Loading @@ -1120,12 +1121,16 @@ public class DataNetworkControllerTest extends TelephonyTest { assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.isOnlyForRoaming).isFalse(); assertThat(handoverRule.networkCapabilities).isEmpty(); handoverRule = new HandoverRule("source= IWLAN, " handoverRule = new HandoverRule("source= IWLAN, " + "target = EUTRAN, type = disallowed, roaming = true"); + "target = EUTRAN, type = disallowed, roaming = true," + " capabilities = IMS | EIMS "); assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.IWLAN); assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.IWLAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); assertThat(handoverRule.networkCapabilities).containsExactly( NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_EIMS); assertThat(handoverRule.isOnlyForRoaming).isTrue(); assertThat(handoverRule.isOnlyForRoaming).isTrue(); assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class, Loading @@ -1145,6 +1150,19 @@ public class DataNetworkControllerTest extends TelephonyTest { assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=IWLAN, target=WTFRAN, type=allowed")); () -> new HandoverRule("source=IWLAN, target=WTFRAN, type=allowed")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=IWLAN, target=|, type=allowed")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=|")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=")); assertThrows(IllegalArgumentException.class, () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, " + "capabilities=wtf")); } } @Test @Test Loading Loading @@ -1364,7 +1382,8 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test @Test public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{"source=EUTRAN, target=IWLAN, type=disallowed"}); new String[]{"source=EUTRAN, target=IWLAN, type=disallowed, capabilities=MMS|IMS", "source=IWLAN, target=EUTRAN, type=disallowed, capabilities=MMS"}); // Force data config manager to reload the carrier config. // Force data config manager to reload the carrier config. mDataNetworkControllerUT.getDataConfigManager().obtainMessage( mDataNetworkControllerUT.getDataConfigManager().obtainMessage( 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); Loading @@ -1391,6 +1410,19 @@ public class DataNetworkControllerTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); assertThat(dataNetworkList.get(0).getTransport()) assertThat(dataNetworkList.get(0).getTransport()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); // test IWLAN -> EUTRAN no need to tear down because the disallowed rule only applies to MMS doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); // After this, IMS data network should be disconnected, and DNC should attempt to // establish a new one on IWLAN processAllMessages(); DataNetwork dataNetwork = getDataNetworks().get(0); // Verify that IWWAN handover succeeded. assertThat(dataNetwork.getTransport()).isEqualTo( AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } } @Test @Test Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -93,4 +93,32 @@ public class DataUtilsTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); } } @Test public void testGetNetworkCapabilitiesFromString() { String normal = " MMS "; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS); String normal2 = "MMS|IMS"; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal2)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_IMS); String normal3 = " MMS |IMS "; assertThat(DataUtils.getNetworkCapabilitiesFromString(normal3)).containsExactly( NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_IMS); String containsUnknown = "MMS |IMS | what"; assertThat(DataUtils.getNetworkCapabilitiesFromString(containsUnknown) .contains(-1)).isTrue(); String malFormatted = ""; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted).contains(-1)).isTrue(); String malFormatted2 = " "; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted2).contains(-1)).isTrue(); String malFormatted3 = "MMS |IMS |"; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted3).contains(-1)).isTrue(); String composedDelim = " | ||"; assertThat(DataUtils.getNetworkCapabilitiesFromString(composedDelim).contains(-1)).isTrue(); String malFormatted4 = "mms||ims"; assertThat(DataUtils.getNetworkCapabilitiesFromString(malFormatted4).contains(-1)).isTrue(); } } }