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