1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.networkstack.tethering; 18 19 import static android.net.ConnectivityManager.TYPE_ETHERNET; 20 import static android.net.ConnectivityManager.TYPE_MOBILE; 21 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; 22 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; 23 import static android.net.ConnectivityManager.TYPE_WIFI; 24 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; 25 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 26 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 29 import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS; 30 import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION; 31 import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION; 32 33 import static org.junit.Assert.assertArrayEquals; 34 import static org.junit.Assert.assertEquals; 35 import static org.junit.Assert.assertFalse; 36 import static org.junit.Assert.assertTrue; 37 import static org.mockito.ArgumentMatchers.anyInt; 38 import static org.mockito.Matchers.eq; 39 import static org.mockito.Mockito.when; 40 41 import android.content.Context; 42 import android.content.pm.ApplicationInfo; 43 import android.content.pm.ModuleInfo; 44 import android.content.pm.PackageInfo; 45 import android.content.pm.PackageManager; 46 import android.content.res.Resources; 47 import android.net.util.SharedLog; 48 import android.os.Build; 49 import android.provider.DeviceConfig; 50 import android.provider.Settings; 51 import android.telephony.TelephonyManager; 52 import android.test.mock.MockContentResolver; 53 54 import androidx.test.filters.SmallTest; 55 import androidx.test.runner.AndroidJUnit4; 56 57 import com.android.internal.util.test.BroadcastInterceptingContext; 58 import com.android.internal.util.test.FakeSettingsProvider; 59 import com.android.net.module.util.DeviceConfigUtils; 60 import com.android.testutils.DevSdkIgnoreRule; 61 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; 62 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 63 64 import org.junit.After; 65 import org.junit.Before; 66 import org.junit.Rule; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.mockito.Mock; 70 import org.mockito.MockitoSession; 71 import org.mockito.quality.Strictness; 72 73 import java.util.Arrays; 74 import java.util.Iterator; 75 76 @RunWith(AndroidJUnit4.class) 77 @SmallTest 78 public class TetheringConfigurationTest { 79 private final SharedLog mLog = new SharedLog("TetheringConfigurationTest"); 80 81 @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 82 83 private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; 84 private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; 85 private static final String PROVISIONING_APP_RESPONSE = "app_response"; 86 private static final String TEST_PACKAGE_NAME = "com.android.tethering.test"; 87 private static final String APEX_NAME = "com.android.tethering"; 88 private static final long TEST_PACKAGE_VERSION = 1234L; 89 @Mock private ApplicationInfo mApplicationInfo; 90 @Mock private Context mContext; 91 @Mock private TelephonyManager mTelephonyManager; 92 @Mock private Resources mResources; 93 @Mock private Resources mResourcesForSubId; 94 @Mock private PackageManager mPackageManager; 95 @Mock private ModuleInfo mMi; 96 private Context mMockContext; 97 private boolean mHasTelephonyManager; 98 private boolean mEnableLegacyDhcpServer; 99 private MockitoSession mMockingSession; 100 private MockContentResolver mContentResolver; 101 102 private class MockTetheringConfiguration extends TetheringConfiguration { MockTetheringConfiguration(Context ctx, SharedLog log, int id)103 MockTetheringConfiguration(Context ctx, SharedLog log, int id) { 104 super(ctx, log, id); 105 } 106 107 @Override getResourcesForSubIdWrapper(Context ctx, int subId)108 protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { 109 return mResourcesForSubId; 110 } 111 } 112 113 private class MockContext extends BroadcastInterceptingContext { MockContext(Context base)114 MockContext(Context base) { 115 super(base); 116 } 117 118 @Override getApplicationInfo()119 public ApplicationInfo getApplicationInfo() { 120 return mApplicationInfo; 121 } 122 123 @Override getResources()124 public Resources getResources() { 125 return mResources; 126 } 127 128 @Override getSystemService(String name)129 public Object getSystemService(String name) { 130 if (Context.TELEPHONY_SERVICE.equals(name)) { 131 return mHasTelephonyManager ? mTelephonyManager : null; 132 } 133 return super.getSystemService(name); 134 } 135 136 @Override getPackageManager()137 public PackageManager getPackageManager() { 138 return mPackageManager; 139 } 140 141 @Override getPackageName()142 public String getPackageName() { 143 return TEST_PACKAGE_NAME; 144 } 145 } 146 147 @Before setUp()148 public void setUp() throws Exception { 149 // TODO: use a dependencies class instead of mock statics. 150 mMockingSession = mockitoSession() 151 .initMocks(this) 152 .mockStatic(DeviceConfig.class) 153 .strictness(Strictness.WARN) 154 .startMocking(); 155 DeviceConfigUtils.resetPackageVersionCacheForTest(); 156 doReturn(null).when( 157 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 158 eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); 159 setTetherForceUpstreamAutomaticFlagVersion(null); 160 161 final PackageInfo pi = new PackageInfo(); 162 pi.setLongVersionCode(TEST_PACKAGE_VERSION); 163 doReturn(pi).when(mPackageManager).getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()); 164 doReturn(mMi).when(mPackageManager).getModuleInfo(eq(APEX_NAME), anyInt()); 165 doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName(); 166 167 when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( 168 new String[0]); 169 when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( 170 TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 171 when(mResources.getStringArray(R.array.config_tether_usb_regexs)) 172 .thenReturn(new String[]{ "test_usb\\d" }); 173 when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) 174 .thenReturn(new String[]{ "test_wlan\\d" }); 175 when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)).thenReturn( 176 new String[0]); 177 when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); 178 when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) 179 .thenReturn(new String[0]); 180 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( 181 false); 182 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) 183 .thenReturn(false); 184 initializeBpfOffloadConfiguration(true, null /* unset */); 185 initEnableSelectAllPrefixRangeFlag(null /* unset */); 186 187 mHasTelephonyManager = true; 188 mMockContext = new MockContext(mContext); 189 mEnableLegacyDhcpServer = false; 190 191 mContentResolver = new MockContentResolver(mMockContext); 192 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 193 when(mContext.getContentResolver()).thenReturn(mContentResolver); 194 // Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider. 195 FakeSettingsProvider.clearSettingsProvider(); 196 } 197 198 @After tearDown()199 public void tearDown() throws Exception { 200 mMockingSession.finishMocking(); 201 DeviceConfigUtils.resetPackageVersionCacheForTest(); 202 // Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider. 203 FakeSettingsProvider.clearSettingsProvider(); 204 } 205 getTetheringConfiguration(int... legacyTetherUpstreamTypes)206 private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { 207 when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( 208 legacyTetherUpstreamTypes); 209 return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 210 } 211 212 @Test testNoTelephonyManagerMeansNoDun()213 public void testNoTelephonyManagerMeansNoDun() { 214 mHasTelephonyManager = false; 215 final TetheringConfiguration cfg = getTetheringConfiguration( 216 new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); 217 assertFalse(cfg.isDunRequired); 218 assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); 219 // Just to prove we haven't clobbered Wi-Fi: 220 assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); 221 } 222 223 @Test testDunFromTelephonyManagerMeansDun()224 public void testDunFromTelephonyManagerMeansDun() { 225 when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true); 226 227 final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); 228 final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( 229 TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI); 230 final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( 231 TYPE_WIFI, TYPE_MOBILE_DUN); 232 final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( 233 TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN); 234 235 for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, 236 cfgWifiDun, cfgMobileWifiHipriDun)) { 237 String msg = "config=" + cfg.toString(); 238 assertTrue(msg, cfg.isDunRequired); 239 assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); 240 assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); 241 assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); 242 // Just to prove we haven't clobbered Wi-Fi: 243 assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); 244 } 245 } 246 247 @Test testDunNotRequiredFromTelephonyManagerMeansNoDun()248 public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { 249 when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); 250 251 final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); 252 final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( 253 TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI); 254 final TetheringConfiguration cfgWifiDun = getTetheringConfiguration( 255 TYPE_WIFI, TYPE_MOBILE_DUN); 256 final TetheringConfiguration cfgWifiMobile = getTetheringConfiguration( 257 TYPE_WIFI, TYPE_MOBILE); 258 final TetheringConfiguration cfgWifiHipri = getTetheringConfiguration( 259 TYPE_WIFI, TYPE_MOBILE_HIPRI); 260 final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration( 261 TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN); 262 263 String msg; 264 // TYPE_MOBILE_DUN should be present in none of the combinations. 265 // TYPE_WIFI should not be affected. 266 for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, 267 cfgWifiMobile, cfgWifiHipri, cfgMobileWifiHipriDun)) { 268 msg = "config=" + cfg.toString(); 269 assertFalse(msg, cfg.isDunRequired); 270 assertFalse(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); 271 assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); 272 } 273 274 for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun, 275 cfgMobileWifiHipriDun)) { 276 msg = "config=" + cfg.toString(); 277 assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); 278 assertTrue(msg, cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); 279 } 280 msg = "config=" + cfgWifiMobile.toString(); 281 assertTrue(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); 282 assertFalse(msg, cfgWifiMobile.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); 283 msg = "config=" + cfgWifiHipri.toString(); 284 assertFalse(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); 285 assertTrue(msg, cfgWifiHipri.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); 286 287 } 288 289 @Test testNoDefinedUpstreamTypesAddsEthernet()290 public void testNoDefinedUpstreamTypesAddsEthernet() { 291 when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[]{}); 292 when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); 293 294 final TetheringConfiguration cfg = new TetheringConfiguration( 295 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 296 final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); 297 assertTrue(upstreamIterator.hasNext()); 298 assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); 299 // The following is because the code always adds some kind of mobile 300 // upstream, be it DUN or, in this case where DUN is NOT required, 301 // make sure there is at least one of MOBILE or HIPRI. With the empty 302 // list of the configuration in this test, it will always add both 303 // MOBILE and HIPRI, in that order. 304 assertTrue(upstreamIterator.hasNext()); 305 assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue()); 306 assertTrue(upstreamIterator.hasNext()); 307 assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); 308 assertFalse(upstreamIterator.hasNext()); 309 } 310 311 @Test testDefinedUpstreamTypesSansEthernetAddsEthernet()312 public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { 313 when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( 314 new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); 315 when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); 316 317 final TetheringConfiguration cfg = new TetheringConfiguration( 318 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 319 final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); 320 assertTrue(upstreamIterator.hasNext()); 321 assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); 322 assertTrue(upstreamIterator.hasNext()); 323 assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); 324 assertTrue(upstreamIterator.hasNext()); 325 assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); 326 assertFalse(upstreamIterator.hasNext()); 327 } 328 329 @Test testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet()330 public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { 331 when(mResources.getIntArray(R.array.config_tether_upstream_types)) 332 .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); 333 when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); 334 335 final TetheringConfiguration cfg = new TetheringConfiguration( 336 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 337 final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator(); 338 assertTrue(upstreamIterator.hasNext()); 339 assertEquals(TYPE_WIFI, upstreamIterator.next().intValue()); 340 assertTrue(upstreamIterator.hasNext()); 341 assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue()); 342 assertTrue(upstreamIterator.hasNext()); 343 assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue()); 344 assertFalse(upstreamIterator.hasNext()); 345 } 346 initializeBpfOffloadConfiguration( final boolean fromRes, final String fromDevConfig)347 private void initializeBpfOffloadConfiguration( 348 final boolean fromRes, final String fromDevConfig) { 349 when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); 350 doReturn(fromDevConfig).when( 351 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 352 eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); 353 } 354 355 @Test testBpfOffloadEnabledByResource()356 public void testBpfOffloadEnabledByResource() { 357 initializeBpfOffloadConfiguration(true, null /* unset */); 358 final TetheringConfiguration enableByRes = 359 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 360 assertTrue(enableByRes.isBpfOffloadEnabled()); 361 } 362 363 @Test testBpfOffloadEnabledByDeviceConfigOverride()364 public void testBpfOffloadEnabledByDeviceConfigOverride() { 365 for (boolean res : new boolean[]{true, false}) { 366 initializeBpfOffloadConfiguration(res, "true"); 367 final TetheringConfiguration enableByDevConOverride = 368 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 369 assertTrue(enableByDevConOverride.isBpfOffloadEnabled()); 370 } 371 } 372 373 @Test testBpfOffloadDisabledByResource()374 public void testBpfOffloadDisabledByResource() { 375 initializeBpfOffloadConfiguration(false, null /* unset */); 376 final TetheringConfiguration disableByRes = 377 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 378 assertFalse(disableByRes.isBpfOffloadEnabled()); 379 } 380 381 @Test testBpfOffloadDisabledByDeviceConfigOverride()382 public void testBpfOffloadDisabledByDeviceConfigOverride() { 383 for (boolean res : new boolean[]{true, false}) { 384 initializeBpfOffloadConfiguration(res, "false"); 385 final TetheringConfiguration disableByDevConOverride = 386 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 387 assertFalse(disableByDevConOverride.isBpfOffloadEnabled()); 388 } 389 } 390 391 @Test testNewDhcpServerDisabled()392 public void testNewDhcpServerDisabled() { 393 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( 394 true); 395 doReturn("false").when( 396 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 397 eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); 398 399 final TetheringConfiguration enableByRes = 400 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 401 assertTrue(enableByRes.enableLegacyDhcpServer); 402 403 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( 404 false); 405 doReturn("true").when( 406 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 407 eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); 408 409 final TetheringConfiguration enableByDevConfig = 410 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 411 assertTrue(enableByDevConfig.enableLegacyDhcpServer); 412 } 413 414 @Test testNewDhcpServerEnabled()415 public void testNewDhcpServerEnabled() { 416 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( 417 false); 418 doReturn("false").when( 419 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 420 eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); 421 422 final TetheringConfiguration cfg = 423 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 424 425 assertFalse(cfg.enableLegacyDhcpServer); 426 } 427 428 @Test testOffloadIntervalByResource()429 public void testOffloadIntervalByResource() { 430 final TetheringConfiguration intervalByDefault = 431 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 432 assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, 433 intervalByDefault.getOffloadPollInterval()); 434 435 final int[] testOverrides = {0, 3000, -1}; 436 for (final int override : testOverrides) { 437 when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn( 438 override); 439 final TetheringConfiguration overrideByRes = 440 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 441 assertEquals(override, overrideByRes.getOffloadPollInterval()); 442 } 443 } 444 445 @Test testGetResourcesBySubId()446 public void testGetResourcesBySubId() { 447 setUpResourceForSubId(); 448 final TetheringConfiguration cfg = new TetheringConfiguration( 449 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 450 assertTrue(cfg.provisioningApp.length == 0); 451 final int anyValidSubId = 1; 452 final MockTetheringConfiguration mockCfg = 453 new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId); 454 assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]); 455 assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]); 456 assertEquals(mockCfg.provisioningAppNoUi, PROVISIONING_NO_UI_APP_NAME); 457 assertEquals(mockCfg.provisioningResponse, PROVISIONING_APP_RESPONSE); 458 } 459 setUpResourceForSubId()460 private void setUpResourceForSubId() { 461 when(mResourcesForSubId.getStringArray( 462 R.array.config_tether_dhcp_range)).thenReturn(new String[0]); 463 when(mResourcesForSubId.getStringArray( 464 R.array.config_tether_usb_regexs)).thenReturn(new String[0]); 465 when(mResourcesForSubId.getStringArray( 466 R.array.config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); 467 when(mResourcesForSubId.getStringArray( 468 R.array.config_tether_bluetooth_regexs)).thenReturn(new String[0]); 469 when(mResourcesForSubId.getIntArray(R.array.config_tether_upstream_types)).thenReturn( 470 new int[0]); 471 when(mResourcesForSubId.getStringArray( 472 R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); 473 when(mResourcesForSubId.getString(R.string.config_mobile_hotspot_provision_app_no_ui)) 474 .thenReturn(PROVISIONING_NO_UI_APP_NAME); 475 when(mResourcesForSubId.getString( 476 R.string.config_mobile_hotspot_provision_response)).thenReturn( 477 PROVISIONING_APP_RESPONSE); 478 } 479 480 @Test testEnableLegacyWifiP2PAddress()481 public void testEnableLegacyWifiP2PAddress() throws Exception { 482 final TetheringConfiguration defaultCfg = new TetheringConfiguration( 483 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 484 assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp()); 485 486 when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) 487 .thenReturn(true); 488 final TetheringConfiguration testCfg = new TetheringConfiguration( 489 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 490 assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp()); 491 } 492 initEnableSelectAllPrefixRangeFlag(final String value)493 private void initEnableSelectAllPrefixRangeFlag(final String value) { 494 doReturn(value).when( 495 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 496 eq(TetheringConfiguration.TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES))); 497 } 498 499 @Test testSelectAllPrefixRangeFlag()500 public void testSelectAllPrefixRangeFlag() throws Exception { 501 // Test default value. 502 final TetheringConfiguration defaultCfg = new TetheringConfiguration( 503 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 504 assertTrue(defaultCfg.isSelectAllPrefixRangeEnabled()); 505 506 // Test disable flag. 507 initEnableSelectAllPrefixRangeFlag("false"); 508 final TetheringConfiguration testDisable = new TetheringConfiguration( 509 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 510 assertFalse(testDisable.isSelectAllPrefixRangeEnabled()); 511 512 // Test enable flag. 513 initEnableSelectAllPrefixRangeFlag("true"); 514 final TetheringConfiguration testEnable = new TetheringConfiguration( 515 mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 516 assertTrue(testEnable.isSelectAllPrefixRangeEnabled()); 517 } 518 519 @Test testChooseUpstreamAutomatically()520 public void testChooseUpstreamAutomatically() throws Exception { 521 when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) 522 .thenReturn(true); 523 assertChooseUpstreamAutomaticallyIs(true); 524 525 when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) 526 .thenReturn(false); 527 assertChooseUpstreamAutomaticallyIs(false); 528 } 529 530 // The flag override only works on R- 531 @Test @IgnoreAfter(Build.VERSION_CODES.R) testChooseUpstreamAutomatically_FlagOverride()532 public void testChooseUpstreamAutomatically_FlagOverride() throws Exception { 533 when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) 534 .thenReturn(false); 535 setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); 536 assertTrue(DeviceConfigUtils.isFeatureEnabled(mMockContext, NAMESPACE_CONNECTIVITY, 537 TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION, APEX_NAME, false)); 538 539 assertChooseUpstreamAutomaticallyIs(true); 540 541 setTetherForceUpstreamAutomaticFlagVersion(0L); 542 assertChooseUpstreamAutomaticallyIs(false); 543 544 setTetherForceUpstreamAutomaticFlagVersion(Long.MAX_VALUE); 545 assertChooseUpstreamAutomaticallyIs(false); 546 } 547 548 @Test @IgnoreUpTo(Build.VERSION_CODES.R) testChooseUpstreamAutomatically_FlagOverrideAfterR()549 public void testChooseUpstreamAutomatically_FlagOverrideAfterR() throws Exception { 550 when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)) 551 .thenReturn(false); 552 setTetherForceUpstreamAutomaticFlagVersion(TEST_PACKAGE_VERSION - 1); 553 assertChooseUpstreamAutomaticallyIs(false); 554 } 555 setTetherForceUpstreamAutomaticFlagVersion(Long version)556 private void setTetherForceUpstreamAutomaticFlagVersion(Long version) { 557 doReturn(version == null ? null : Long.toString(version)).when( 558 () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), 559 eq(TetheringConfiguration.TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION))); 560 } 561 assertChooseUpstreamAutomaticallyIs(boolean value)562 private void assertChooseUpstreamAutomaticallyIs(boolean value) { 563 assertEquals(value, new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID) 564 .chooseUpstreamAutomatically); 565 } 566 567 @Test testUsbTetheringFunctions()568 public void testUsbTetheringFunctions() throws Exception { 569 // Test default value. If both resource and settings is not configured, usingNcm is false. 570 assertIsUsingNcm(false /* usingNcm */); 571 572 when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( 573 TETHER_USB_NCM_FUNCTION); 574 assertIsUsingNcm(true /* usingNcm */); 575 576 when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( 577 TETHER_USB_RNDIS_FUNCTION); 578 assertIsUsingNcm(false /* usingNcm */); 579 580 setTetherForceUsbFunctions(TETHER_USB_RNDIS_FUNCTION); 581 assertIsUsingNcm(false /* usingNcm */); 582 583 setTetherForceUsbFunctions(TETHER_USB_NCM_FUNCTION); 584 assertIsUsingNcm(true /* usingNcm */); 585 586 // Test throws NumberFormatException. 587 setTetherForceUsbFunctions("WrongNumberFormat"); 588 assertIsUsingNcm(false /* usingNcm */); 589 } 590 assertIsUsingNcm(boolean expected)591 private void assertIsUsingNcm(boolean expected) { 592 final TetheringConfiguration cfg = 593 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 594 assertEquals(expected, cfg.isUsingNcm()); 595 } 596 setTetherForceUsbFunctions(final String value)597 private void setTetherForceUsbFunctions(final String value) { 598 Settings.Global.putString(mContentResolver, TETHER_FORCE_USB_FUNCTIONS, value); 599 } 600 setTetherForceUsbFunctions(final int value)601 private void setTetherForceUsbFunctions(final int value) { 602 setTetherForceUsbFunctions(Integer.toString(value)); 603 } 604 605 @Test testNcmRegexs()606 public void testNcmRegexs() throws Exception { 607 final String[] rndisRegexs = {"test_rndis\\d"}; 608 final String[] ncmRegexs = {"test_ncm\\d"}; 609 final String[] rndisNcmRegexs = {"test_rndis\\d", "test_ncm\\d"}; 610 611 // cfg.isUsingNcm = false. 612 when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( 613 TETHER_USB_RNDIS_FUNCTION); 614 setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); 615 assertUsbAndNcmRegexs(rndisRegexs, ncmRegexs); 616 617 setUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); 618 assertUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); 619 620 // cfg.isUsingNcm = true. 621 when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn( 622 TETHER_USB_NCM_FUNCTION); 623 setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); 624 assertUsbAndNcmRegexs(ncmRegexs, new String[0]); 625 626 setUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); 627 assertUsbAndNcmRegexs(rndisNcmRegexs, new String[0]); 628 629 // Check USB regex is not overwritten by the NCM regex after force to use rndis from 630 // Settings. 631 setUsbAndNcmRegexs(rndisRegexs, ncmRegexs); 632 setTetherForceUsbFunctions(TETHER_USB_RNDIS_FUNCTION); 633 assertUsbAndNcmRegexs(rndisRegexs, ncmRegexs); 634 } 635 setUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs)636 private void setUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs) { 637 when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(usbRegexs); 638 when(mResources.getStringArray(R.array.config_tether_ncm_regexs)).thenReturn(ncmRegexs); 639 } 640 assertUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs)641 private void assertUsbAndNcmRegexs(final String[] usbRegexs, final String[] ncmRegexs) { 642 final TetheringConfiguration cfg = 643 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); 644 assertArrayEquals(usbRegexs, cfg.tetherableUsbRegexs); 645 assertArrayEquals(ncmRegexs, cfg.tetherableNcmRegexs); 646 } 647 648 } 649