Loading core/res/res/values/config.xml +10 −16 Original line number Diff line number Diff line Loading @@ -477,22 +477,16 @@ - the return value of TelephonyManager.getTetherApnRequired() determines how the array is further modified: * DUN_REQUIRED TYPE_MOBILE is removed (if present) TYPE_MOBILE_HIPRI is removed (if present) TYPE_MOBILE_DUN is appended (if not already present) * DUN_NOT_REQUIRED TYPE_MOBILE_DUN is removed (if present) TYPE_MOBILE is appended (if not already present) TYPE_MOBILE_HIPRI is appended (if not already present) * DUN_UNSPECIFIED if any of TYPE_MOBILE{,_DUN,_HIPRI} are present: change nothing else: TYPE_MOBILE is appended TYPE_MOBILE_HIPRI is appended * TRUE (DUN REQUIRED). TYPE_MOBILE is removed (if present). TYPE_MOBILE_HIPRI is removed (if present). TYPE_MOBILE_DUN is appended (if not already present). * FALSE (DUN NOT REQUIRED). TYPE_MOBILE_DUN is removed (if present). If both of TYPE_MOBILE{,_HIPRI} are not present: TYPE_MOBILE is appended. TYPE_MOBILE_HIPRI is appended. For other changes applied to this list, now and in the future, see com.android.server.connectivity.tethering.TetheringConfiguration. Loading services/core/java/com/android/server/connectivity/Tethering.java +2 −2 Original line number Diff line number Diff line Loading @@ -289,8 +289,8 @@ public class Tethering extends BaseNetworkObserver { } private void maybeUpdateConfiguration() { final int dunCheck = TetheringConfiguration.checkDunRequired(mContext); if (dunCheck == mConfig.dunCheck) return; final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext); if (isDunRequired == mConfig.isDunRequired) return; updateConfiguration(); } Loading services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +15 −33 Original line number Diff line number Diff line Loading @@ -67,11 +67,6 @@ public class TetheringConfiguration { private static final String[] EMPTY_STRING_ARRAY = new String[0]; @VisibleForTesting public static final int DUN_NOT_REQUIRED = 0; public static final int DUN_REQUIRED = 1; public static final int DUN_UNSPECIFIED = 2; // Default ranges used for the legacy DHCP server. // USB is 192.168.42.1 and 255.255.255.0 // Wifi is 192.168.43.1 and 255.255.255.0 Loading @@ -90,7 +85,6 @@ public class TetheringConfiguration { public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; public final String[] tetherableBluetoothRegexs; public final int dunCheck; public final boolean isDunRequired; public final boolean chooseUpstreamAutomatically; public final Collection<Integer> preferredUpstreamIfaceTypes; Loading @@ -116,12 +110,10 @@ public class TetheringConfiguration { tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); dunCheck = checkDunRequired(ctx); configLog.log("DUN check returned: " + dunCheckString(dunCheck)); isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck); isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); Loading Loading @@ -230,53 +222,43 @@ public class TetheringConfiguration { return upstreamNames; } public static int checkDunRequired(Context ctx) { /** Check whether dun is required. */ public static boolean checkDunRequired(Context ctx) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; } private static String dunCheckString(int dunCheck) { switch (dunCheck) { case DUN_NOT_REQUIRED: return "DUN_NOT_REQUIRED"; case DUN_REQUIRED: return "DUN_REQUIRED"; case DUN_UNSPECIFIED: return "DUN_UNSPECIFIED"; default: return String.format("UNKNOWN (%s)", dunCheck); } return (tm != null) ? tm.getTetherApnRequired() : false; } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) { private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { case TYPE_MOBILE: case TYPE_MOBILE_HIPRI: if (dunCheck == DUN_REQUIRED) continue; if (dunRequired) continue; break; case TYPE_MOBILE_DUN: if (dunCheck == DUN_NOT_REQUIRED) continue; if (!dunRequired) continue; break; } upstreamIfaceTypes.add(i); } // Fix up upstream interface types for DUN or mobile. NOTE: independent // of the value of |dunCheck|, cell data of one form or another is // of the value of |dunRequired|, cell data of one form or another is // *always* an upstream, regardless of the upstream interface types // specified by configuration resources. if (dunCheck == DUN_REQUIRED) { if (dunRequired) { appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN); } else if (dunCheck == DUN_NOT_REQUIRED) { appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE); appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_HIPRI); } else { // Fix upstream interface types for case DUN_UNSPECIFIED. // Do not modify if a cellular interface type is already present in the // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no // cellular interface types are found in the upstream interface types. if (!(containsOneOf(upstreamIfaceTypes, TYPE_MOBILE_DUN, TYPE_MOBILE, TYPE_MOBILE_HIPRI))) { // This preserves backwards compatibility and prevents the DUN and default // mobile types incorrectly appearing together, which could happen on // previous releases in the common case where checkDunRequired returned // DUN_UNSPECIFIED. if (!containsOneOf(upstreamIfaceTypes, TYPE_MOBILE, TYPE_MOBILE_HIPRI)) { upstreamIfaceTypes.add(TYPE_MOBILE); upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI); } Loading tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +86 −60 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED; import static com.android.internal.R.array.config_tether_upstream_types; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; Loading @@ -52,6 +50,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Iterator; @RunWith(AndroidJUnit4.class) Loading Loading @@ -112,74 +111,103 @@ public class TetheringConfigurationTest { .thenReturn(new String[]{ "test_wlan\\d" }); when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); when(mResources.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[0]); mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); } @Test public void testDunFromTelephonyManagerMeansDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); private TetheringConfiguration getTetheringConfiguration(int[] legacyTetherUpstreamTypes) { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( legacyTetherUpstreamTypes); return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); } @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); public void testNoTelephonyManagerMeansNoDun() { mHasTelephonyManager = false; final TetheringConfiguration cfg = getTetheringConfiguration( new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); assertFalse(cfg.isDunRequired); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } @Test public void testDunFromUpstreamConfigMeansDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); public void testDunFromTelephonyManagerMeansDun() { when(mTelephonyManager.getTetherApnRequired()).thenReturn(true); final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI}); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_DUN}); final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN}); for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgMobileWifiHipriDun)) { String msg = "config=" + cfg.toString(); assertTrue(msg, cfg.isDunRequired); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); // Check that we have not added new cellular interface types assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } } @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI}); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_DUN}); final TetheringConfiguration cfgWifiMobile = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE}); final TetheringConfiguration cfgWifiHipri = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN}); String msg; // TYPE_MOBILE_DUN should not be present in all of the combinations. // TYPE_WIFI should not be affected. for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgWifiMobile, cfgWifiHipri, cfgMobileWifiHipriDun)) { msg = "config=" + cfg.toString(); assertFalse(msg, cfg.isDunRequired); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgMobileWifiHipriDun)) { msg = "config=" + cfg.toString(); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); } msg = "config=" + cfgWifiMobile.toString(); assertTrue(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); msg = "config=" + cfgWifiHipri.toString(); assertFalse(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); } @Test public void testNoDefinedUpstreamTypesAddsEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading @@ -187,8 +215,10 @@ public class TetheringConfigurationTest { assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); // The following is because the code always adds some kind of mobile // upstream, be it DUN or, in this case where we use DUN_UNSPECIFIED, // both vanilla and hipri mobile types. // upstream, be it DUN or, in this case where DUN is NOT required, // make sure there is at least one of MOBILE or HIPRI. With the empty // list of the configuration in this test, it will always add both // MOBILE and HIPRI, in that order. assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue()); assertTrue(upstreamIterator.hasNext()); Loading @@ -198,10 +228,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading @@ -217,10 +246,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) when(mResources.getIntArray(config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading Loading @@ -276,9 +304,7 @@ public class TetheringConfigurationTest { when(mResourcesForSubId.getStringArray( com.android.internal.R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); when(mResourcesForSubId.getIntArray( com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); when(mResourcesForSubId.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app)) .thenReturn(PROVISIONING_APP_NAME); Loading Loading
core/res/res/values/config.xml +10 −16 Original line number Diff line number Diff line Loading @@ -477,22 +477,16 @@ - the return value of TelephonyManager.getTetherApnRequired() determines how the array is further modified: * DUN_REQUIRED TYPE_MOBILE is removed (if present) TYPE_MOBILE_HIPRI is removed (if present) TYPE_MOBILE_DUN is appended (if not already present) * DUN_NOT_REQUIRED TYPE_MOBILE_DUN is removed (if present) TYPE_MOBILE is appended (if not already present) TYPE_MOBILE_HIPRI is appended (if not already present) * DUN_UNSPECIFIED if any of TYPE_MOBILE{,_DUN,_HIPRI} are present: change nothing else: TYPE_MOBILE is appended TYPE_MOBILE_HIPRI is appended * TRUE (DUN REQUIRED). TYPE_MOBILE is removed (if present). TYPE_MOBILE_HIPRI is removed (if present). TYPE_MOBILE_DUN is appended (if not already present). * FALSE (DUN NOT REQUIRED). TYPE_MOBILE_DUN is removed (if present). If both of TYPE_MOBILE{,_HIPRI} are not present: TYPE_MOBILE is appended. TYPE_MOBILE_HIPRI is appended. For other changes applied to this list, now and in the future, see com.android.server.connectivity.tethering.TetheringConfiguration. Loading
services/core/java/com/android/server/connectivity/Tethering.java +2 −2 Original line number Diff line number Diff line Loading @@ -289,8 +289,8 @@ public class Tethering extends BaseNetworkObserver { } private void maybeUpdateConfiguration() { final int dunCheck = TetheringConfiguration.checkDunRequired(mContext); if (dunCheck == mConfig.dunCheck) return; final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext); if (isDunRequired == mConfig.isDunRequired) return; updateConfiguration(); } Loading
services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +15 −33 Original line number Diff line number Diff line Loading @@ -67,11 +67,6 @@ public class TetheringConfiguration { private static final String[] EMPTY_STRING_ARRAY = new String[0]; @VisibleForTesting public static final int DUN_NOT_REQUIRED = 0; public static final int DUN_REQUIRED = 1; public static final int DUN_UNSPECIFIED = 2; // Default ranges used for the legacy DHCP server. // USB is 192.168.42.1 and 255.255.255.0 // Wifi is 192.168.43.1 and 255.255.255.0 Loading @@ -90,7 +85,6 @@ public class TetheringConfiguration { public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; public final String[] tetherableBluetoothRegexs; public final int dunCheck; public final boolean isDunRequired; public final boolean chooseUpstreamAutomatically; public final Collection<Integer> preferredUpstreamIfaceTypes; Loading @@ -116,12 +110,10 @@ public class TetheringConfiguration { tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); dunCheck = checkDunRequired(ctx); configLog.log("DUN check returned: " + dunCheckString(dunCheck)); isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck); isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); Loading Loading @@ -230,53 +222,43 @@ public class TetheringConfiguration { return upstreamNames; } public static int checkDunRequired(Context ctx) { /** Check whether dun is required. */ public static boolean checkDunRequired(Context ctx) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; } private static String dunCheckString(int dunCheck) { switch (dunCheck) { case DUN_NOT_REQUIRED: return "DUN_NOT_REQUIRED"; case DUN_REQUIRED: return "DUN_REQUIRED"; case DUN_UNSPECIFIED: return "DUN_UNSPECIFIED"; default: return String.format("UNKNOWN (%s)", dunCheck); } return (tm != null) ? tm.getTetherApnRequired() : false; } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) { private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { case TYPE_MOBILE: case TYPE_MOBILE_HIPRI: if (dunCheck == DUN_REQUIRED) continue; if (dunRequired) continue; break; case TYPE_MOBILE_DUN: if (dunCheck == DUN_NOT_REQUIRED) continue; if (!dunRequired) continue; break; } upstreamIfaceTypes.add(i); } // Fix up upstream interface types for DUN or mobile. NOTE: independent // of the value of |dunCheck|, cell data of one form or another is // of the value of |dunRequired|, cell data of one form or another is // *always* an upstream, regardless of the upstream interface types // specified by configuration resources. if (dunCheck == DUN_REQUIRED) { if (dunRequired) { appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN); } else if (dunCheck == DUN_NOT_REQUIRED) { appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE); appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_HIPRI); } else { // Fix upstream interface types for case DUN_UNSPECIFIED. // Do not modify if a cellular interface type is already present in the // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no // cellular interface types are found in the upstream interface types. if (!(containsOneOf(upstreamIfaceTypes, TYPE_MOBILE_DUN, TYPE_MOBILE, TYPE_MOBILE_HIPRI))) { // This preserves backwards compatibility and prevents the DUN and default // mobile types incorrectly appearing together, which could happen on // previous releases in the common case where checkDunRequired returned // DUN_UNSPECIFIED. if (!containsOneOf(upstreamIfaceTypes, TYPE_MOBILE, TYPE_MOBILE_HIPRI)) { upstreamIfaceTypes.add(TYPE_MOBILE); upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI); } Loading
tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +86 −60 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED; import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED; import static com.android.internal.R.array.config_tether_upstream_types; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; Loading @@ -52,6 +50,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Iterator; @RunWith(AndroidJUnit4.class) Loading Loading @@ -112,74 +111,103 @@ public class TetheringConfigurationTest { .thenReturn(new String[]{ "test_wlan\\d" }); when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); when(mResources.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[0]); mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); } @Test public void testDunFromTelephonyManagerMeansDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); private TetheringConfiguration getTetheringConfiguration(int[] legacyTetherUpstreamTypes) { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( legacyTetherUpstreamTypes); return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); } @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); mHasTelephonyManager = true; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); public void testNoTelephonyManagerMeansNoDun() { mHasTelephonyManager = false; final TetheringConfiguration cfg = getTetheringConfiguration( new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); assertFalse(cfg.isDunRequired); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } @Test public void testDunFromUpstreamConfigMeansDun() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(cfg.isDunRequired); assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); public void testDunFromTelephonyManagerMeansDun() { when(mTelephonyManager.getTetherApnRequired()).thenReturn(true); final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI}); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_DUN}); final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN}); for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgMobileWifiHipriDun)) { String msg = "config=" + cfg.toString(); assertTrue(msg, cfg.isDunRequired); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); // Just to prove we haven't clobbered Wi-Fi: assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); // Check that we have not added new cellular interface types assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } } @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI}); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_DUN}); final TetheringConfiguration cfgWifiMobile = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE}); final TetheringConfiguration cfgWifiHipri = getTetheringConfiguration( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN}); String msg; // TYPE_MOBILE_DUN should not be present in all of the combinations. // TYPE_WIFI should not be affected. for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgWifiMobile, cfgWifiHipri, cfgMobileWifiHipriDun)) { msg = "config=" + cfg.toString(); assertFalse(msg, cfg.isDunRequired); assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); } for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, cfgMobileWifiHipriDun)) { msg = "config=" + cfg.toString(); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); } msg = "config=" + cfgWifiMobile.toString(); assertTrue(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertFalse(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); msg = "config=" + cfgWifiHipri.toString(); assertFalse(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); assertTrue(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); } @Test public void testNoDefinedUpstreamTypesAddsEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading @@ -187,8 +215,10 @@ public class TetheringConfigurationTest { assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); // The following is because the code always adds some kind of mobile // upstream, be it DUN or, in this case where we use DUN_UNSPECIFIED, // both vanilla and hipri mobile types. // upstream, be it DUN or, in this case where DUN is NOT required, // make sure there is at least one of MOBILE or HIPRI. With the empty // list of the configuration in this test, it will always add both // MOBILE and HIPRI, in that order. assertTrue(upstreamIterator.hasNext()); assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue()); assertTrue(upstreamIterator.hasNext()); Loading @@ -198,10 +228,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading @@ -217,10 +246,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) when(mResources.getIntArray(config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); mHasTelephonyManager = false; when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); when(mTelephonyManager.getTetherApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); Loading Loading @@ -276,9 +304,7 @@ public class TetheringConfigurationTest { when(mResourcesForSubId.getStringArray( com.android.internal.R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); when(mResourcesForSubId.getIntArray( com.android.internal.R.array.config_tether_upstream_types)) .thenReturn(new int[0]); when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); when(mResourcesForSubId.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app)) .thenReturn(PROVISIONING_APP_NAME); Loading