1 /* 2 * Copyright (C) 2019 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 package android.tethering.test; 17 18 import static android.Manifest.permission.MODIFY_PHONE_STATE; 19 import static android.Manifest.permission.TETHER_PRIVILEGED; 20 import static android.content.pm.PackageManager.FEATURE_TELEPHONY; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 23 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 24 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 25 import static android.net.TetheringManager.TETHERING_USB; 26 import static android.net.TetheringManager.TETHERING_WIFI; 27 import static android.net.TetheringManager.TETHERING_WIFI_P2P; 28 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; 29 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; 30 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; 31 import static android.net.cts.util.CtsTetheringUtils.isAnyIfaceMatch; 32 33 import static com.android.testutils.TestPermissionUtil.runAsShell; 34 35 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertFalse; 37 import static org.junit.Assert.assertNotNull; 38 import static org.junit.Assert.assertNull; 39 import static org.junit.Assert.assertTrue; 40 import static org.junit.Assert.fail; 41 import static org.junit.Assume.assumeFalse; 42 import static org.junit.Assume.assumeTrue; 43 44 import android.content.BroadcastReceiver; 45 import android.content.Context; 46 import android.content.Intent; 47 import android.content.IntentFilter; 48 import android.content.pm.PackageManager; 49 import android.net.ConnectivityManager; 50 import android.net.LinkAddress; 51 import android.net.Network; 52 import android.net.NetworkCapabilities; 53 import android.net.TetheringInterface; 54 import android.net.TetheringManager; 55 import android.net.TetheringManager.OnTetheringEntitlementResultListener; 56 import android.net.TetheringManager.TetheringInterfaceRegexps; 57 import android.net.TetheringManager.TetheringRequest; 58 import android.net.cts.util.CtsNetUtils; 59 import android.net.cts.util.CtsNetUtils.TestNetworkCallback; 60 import android.net.cts.util.CtsTetheringUtils; 61 import android.net.cts.util.CtsTetheringUtils.StartTetheringCallback; 62 import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; 63 import android.net.wifi.WifiManager; 64 import android.os.Bundle; 65 import android.os.PersistableBundle; 66 import android.os.ResultReceiver; 67 import android.telephony.CarrierConfigManager; 68 import android.telephony.SubscriptionManager; 69 import android.telephony.TelephonyManager; 70 71 import androidx.test.InstrumentationRegistry; 72 import androidx.test.runner.AndroidJUnit4; 73 74 import com.android.testutils.ParcelUtils; 75 76 import org.junit.After; 77 import org.junit.Before; 78 import org.junit.Test; 79 import org.junit.runner.RunWith; 80 81 import java.util.ArrayList; 82 import java.util.Arrays; 83 import java.util.List; 84 import java.util.concurrent.CompletableFuture; 85 import java.util.concurrent.LinkedBlockingQueue; 86 import java.util.concurrent.TimeUnit; 87 import java.util.function.Consumer; 88 89 @RunWith(AndroidJUnit4.class) 90 public class TetheringManagerTest { 91 92 private Context mContext; 93 94 private ConnectivityManager mCm; 95 private TetheringManager mTM; 96 private WifiManager mWm; 97 private PackageManager mPm; 98 99 private TetherChangeReceiver mTetherChangeReceiver; 100 private CtsNetUtils mCtsNetUtils; 101 private CtsTetheringUtils mCtsTetheringUtils; 102 103 private static final int DEFAULT_TIMEOUT_MS = 60_000; 104 105 @Before setUp()106 public void setUp() throws Exception { 107 mContext = InstrumentationRegistry.getContext(); 108 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 109 mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); 110 mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 111 mPm = mContext.getPackageManager(); 112 mCtsNetUtils = new CtsNetUtils(mContext); 113 mCtsTetheringUtils = new CtsTetheringUtils(mContext); 114 mTetherChangeReceiver = new TetherChangeReceiver(); 115 final IntentFilter filter = new IntentFilter( 116 TetheringManager.ACTION_TETHER_STATE_CHANGED); 117 final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter); 118 if (intent != null) mTetherChangeReceiver.onReceive(null, intent); 119 } 120 121 @After tearDown()122 public void tearDown() throws Exception { 123 mCtsTetheringUtils.stopAllTethering(); 124 mContext.unregisterReceiver(mTetherChangeReceiver); 125 } 126 127 private class TetherChangeReceiver extends BroadcastReceiver { 128 private class TetherState { 129 final ArrayList<String> mAvailable; 130 final ArrayList<String> mActive; 131 final ArrayList<String> mErrored; 132 TetherState(Intent intent)133 TetherState(Intent intent) { 134 mAvailable = intent.getStringArrayListExtra( 135 TetheringManager.EXTRA_AVAILABLE_TETHER); 136 mActive = intent.getStringArrayListExtra( 137 TetheringManager.EXTRA_ACTIVE_TETHER); 138 mErrored = intent.getStringArrayListExtra( 139 TetheringManager.EXTRA_ERRORED_TETHER); 140 } 141 } 142 143 @Override onReceive(Context content, Intent intent)144 public void onReceive(Context content, Intent intent) { 145 String action = intent.getAction(); 146 if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) { 147 mResult.add(new TetherState(intent)); 148 } 149 } 150 151 public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>(); 152 153 // Expects that tethering reaches the desired state. 154 // - If active is true, expects that tethering is enabled on at least one interface 155 // matching ifaceRegexs. 156 // - If active is false, expects that tethering is disabled on all the interfaces matching 157 // ifaceRegexs. 158 // Fails if any interface matching ifaceRegexs becomes errored. expectTethering(final boolean active, final String[] ifaceRegexs)159 public void expectTethering(final boolean active, final String[] ifaceRegexs) { 160 while (true) { 161 final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs); 162 assertNotNull("Did not receive expected state change, active: " + active, state); 163 164 if (isIfaceActive(ifaceRegexs, state) == active) return; 165 } 166 } 167 pollAndAssertNoError(final int timeout, final String[] ifaceRegexs)168 private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) { 169 final TetherState state = pollTetherState(timeout); 170 assertNoErroredIfaces(state, ifaceRegexs); 171 return state; 172 } 173 pollTetherState(final int timeout)174 private TetherState pollTetherState(final int timeout) { 175 try { 176 return mResult.poll(timeout, TimeUnit.MILLISECONDS); 177 } catch (InterruptedException e) { 178 fail("No result after " + timeout + " ms"); 179 return null; 180 } 181 } 182 isIfaceActive(final String[] ifaceRegexs, final TetherState state)183 private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) { 184 return isAnyIfaceMatch(ifaceRegexs, state.mActive); 185 } 186 assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs)187 private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) { 188 if (state == null || state.mErrored == null) return; 189 190 if (isAnyIfaceMatch(ifaceRegexs, state.mErrored)) { 191 fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray())); 192 } 193 } 194 } 195 196 @Test testStartTetheringWithStateChangeBroadcast()197 public void testStartTetheringWithStateChangeBroadcast() throws Exception { 198 final TestTetheringEventCallback tetherEventCallback = 199 mCtsTetheringUtils.registerTetheringEventCallback(); 200 try { 201 tetherEventCallback.assumeWifiTetheringSupported(mContext); 202 tetherEventCallback.expectNoTetheringActive(); 203 204 final String[] wifiRegexs = mTM.getTetherableWifiRegexs(); 205 mCtsTetheringUtils.startWifiTethering(tetherEventCallback); 206 207 mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); 208 209 mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); 210 mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs); 211 } finally { 212 mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); 213 } 214 215 } 216 217 @Test testTetheringRequest()218 public void testTetheringRequest() { 219 final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI).build(); 220 assertEquals(TETHERING_WIFI, tr.getTetheringType()); 221 assertNull(tr.getLocalIpv4Address()); 222 assertNull(tr.getClientStaticIpv4Address()); 223 assertFalse(tr.isExemptFromEntitlementCheck()); 224 assertTrue(tr.getShouldShowEntitlementUi()); 225 226 final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); 227 final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); 228 final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB) 229 .setStaticIpv4Addresses(localAddr, clientAddr) 230 .setExemptFromEntitlementCheck(true) 231 .setShouldShowEntitlementUi(false).build(); 232 233 assertEquals(localAddr, tr2.getLocalIpv4Address()); 234 assertEquals(clientAddr, tr2.getClientStaticIpv4Address()); 235 assertEquals(TETHERING_USB, tr2.getTetheringType()); 236 assertTrue(tr2.isExemptFromEntitlementCheck()); 237 assertFalse(tr2.getShouldShowEntitlementUi()); 238 } 239 240 @Test testTetheringRequestParcelable()241 public void testTetheringRequestParcelable() { 242 final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); 243 final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); 244 final TetheringRequest unparceled = new TetheringRequest.Builder(TETHERING_USB) 245 .setStaticIpv4Addresses(localAddr, clientAddr) 246 .setExemptFromEntitlementCheck(true) 247 .setShouldShowEntitlementUi(false).build(); 248 final TetheringRequest parceled = ParcelUtils.parcelingRoundTrip(unparceled); 249 assertEquals(unparceled.getTetheringType(), parceled.getTetheringType()); 250 assertEquals(unparceled.getConnectivityScope(), parceled.getConnectivityScope()); 251 assertEquals(unparceled.getLocalIpv4Address(), parceled.getLocalIpv4Address()); 252 assertEquals(unparceled.getClientStaticIpv4Address(), 253 parceled.getClientStaticIpv4Address()); 254 assertEquals(unparceled.isExemptFromEntitlementCheck(), 255 parceled.isExemptFromEntitlementCheck()); 256 assertEquals(unparceled.getShouldShowEntitlementUi(), 257 parceled.getShouldShowEntitlementUi()); 258 } 259 260 @Test testRegisterTetheringEventCallback()261 public void testRegisterTetheringEventCallback() throws Exception { 262 final TestTetheringEventCallback tetherEventCallback = 263 mCtsTetheringUtils.registerTetheringEventCallback(); 264 265 try { 266 tetherEventCallback.assumeWifiTetheringSupported(mContext); 267 tetherEventCallback.expectNoTetheringActive(); 268 269 final TetheringInterface tetheredIface = 270 mCtsTetheringUtils.startWifiTethering(tetherEventCallback); 271 272 assertNotNull(tetheredIface); 273 final String wifiTetheringIface = tetheredIface.getInterface(); 274 275 mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); 276 277 try { 278 final int ret = runAsShell(TETHER_PRIVILEGED, () -> mTM.tether(wifiTetheringIface)); 279 // There is no guarantee that the wifi interface will be available after disabling 280 // the hotspot, so don't fail the test if the call to tether() fails. 281 if (ret == TETHER_ERROR_NO_ERROR) { 282 // If calling #tether successful, there is a callback to tell the result of 283 // tethering setup. 284 tetherEventCallback.expectErrorOrTethered( 285 new TetheringInterface(TETHERING_WIFI, wifiTetheringIface)); 286 } 287 } finally { 288 runAsShell(TETHER_PRIVILEGED, () -> mTM.untether(wifiTetheringIface)); 289 } 290 } finally { 291 mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); 292 } 293 } 294 295 @Test testGetTetherableInterfaceRegexps()296 public void testGetTetherableInterfaceRegexps() { 297 final TestTetheringEventCallback tetherEventCallback = 298 mCtsTetheringUtils.registerTetheringEventCallback(); 299 tetherEventCallback.assumeTetheringSupported(); 300 301 final TetheringInterfaceRegexps tetherableRegexs = 302 tetherEventCallback.getTetheringInterfaceRegexps(); 303 final List<String> wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); 304 final List<String> usbRegexs = tetherableRegexs.getTetherableUsbRegexs(); 305 final List<String> btRegexs = tetherableRegexs.getTetherableBluetoothRegexs(); 306 307 assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs())); 308 assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs())); 309 assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs())); 310 311 //Verify that any regex name should only contain in one array. 312 wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s))); 313 wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); 314 usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); 315 316 mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); 317 } 318 319 @Test testStopAllTethering()320 public void testStopAllTethering() throws Exception { 321 final TestTetheringEventCallback tetherEventCallback = 322 mCtsTetheringUtils.registerTetheringEventCallback(); 323 try { 324 tetherEventCallback.assumeWifiTetheringSupported(mContext); 325 326 // TODO: start ethernet tethering here when TetheringManagerTest is moved to 327 // TetheringIntegrationTest. 328 329 mCtsTetheringUtils.startWifiTethering(tetherEventCallback); 330 331 mCtsTetheringUtils.stopAllTethering(); 332 tetherEventCallback.expectNoTetheringActive(); 333 } finally { 334 mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); 335 } 336 } 337 338 @Test testEnableTetheringPermission()339 public void testEnableTetheringPermission() throws Exception { 340 final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); 341 mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), 342 c -> c.run() /* executor */, startTetheringCallback); 343 startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); 344 } 345 346 private class EntitlementResultListener implements OnTetheringEntitlementResultListener { 347 private final CompletableFuture<Integer> future = new CompletableFuture<>(); 348 349 @Override onTetheringEntitlementResult(int result)350 public void onTetheringEntitlementResult(int result) { 351 future.complete(result); 352 } 353 get(long timeout, TimeUnit unit)354 public int get(long timeout, TimeUnit unit) throws Exception { 355 return future.get(timeout, unit); 356 } 357 358 } 359 assertEntitlementResult(final Consumer<EntitlementResultListener> functor, final int expect)360 private void assertEntitlementResult(final Consumer<EntitlementResultListener> functor, 361 final int expect) throws Exception { 362 runAsShell(TETHER_PRIVILEGED, () -> { 363 final EntitlementResultListener listener = new EntitlementResultListener(); 364 functor.accept(listener); 365 366 assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 367 }); 368 } 369 isTetheringSupported()370 private boolean isTetheringSupported() { 371 return runAsShell(TETHER_PRIVILEGED, () -> mTM.isTetheringSupported()); 372 } 373 374 @Test testRequestLatestEntitlementResult()375 public void testRequestLatestEntitlementResult() throws Exception { 376 assumeTrue(isTetheringSupported()); 377 assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); 378 // Verify that requestLatestTetheringEntitlementResult() can get entitlement 379 // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener. 380 assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( 381 TETHERING_WIFI_P2P, false, c -> c.run(), listener), 382 TETHER_ERROR_ENTITLEMENT_UNKNOWN); 383 384 // Verify that requestLatestTetheringEntitlementResult() can get entitlement 385 // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver. 386 assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( 387 TETHERING_WIFI_P2P, 388 new ResultReceiver(null /* handler */) { 389 @Override 390 public void onReceiveResult(int resultCode, Bundle resultData) { 391 listener.onTetheringEntitlementResult(resultCode); 392 } 393 }, false), 394 TETHER_ERROR_ENTITLEMENT_UNKNOWN); 395 396 // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available. 397 assumeTrue(mTM.getTetherableWifiRegexs().length > 0); 398 399 // Verify that null listener will cause IllegalArgumentException. 400 try { 401 mTM.requestLatestTetheringEntitlementResult( 402 TETHERING_WIFI, false, c -> c.run(), null); 403 } catch (IllegalArgumentException expect) { } 404 405 // Override carrier config to ignore entitlement check. 406 final PersistableBundle bundle = new PersistableBundle(); 407 bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false); 408 overrideCarrierConfig(bundle); 409 410 // Verify that requestLatestTetheringEntitlementResult() can get entitlement 411 // result TETHER_ERROR_NO_ERROR due to provisioning bypassed. 412 assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult( 413 TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR); 414 415 // Reset carrier config. 416 overrideCarrierConfig(null); 417 } 418 overrideCarrierConfig(PersistableBundle bundle)419 private void overrideCarrierConfig(PersistableBundle bundle) { 420 final CarrierConfigManager configManager = (CarrierConfigManager) mContext 421 .getSystemService(Context.CARRIER_CONFIG_SERVICE); 422 final int subId = SubscriptionManager.getDefaultSubscriptionId(); 423 runAsShell(MODIFY_PHONE_STATE, () -> configManager.overrideConfig(subId, bundle)); 424 } 425 isTetheringApnRequired()426 private boolean isTetheringApnRequired() { 427 final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 428 return runAsShell(MODIFY_PHONE_STATE, () -> tm.isTetheringApnRequired()); 429 430 } 431 432 @Test testTetheringUpstream()433 public void testTetheringUpstream() throws Exception { 434 assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY)); 435 final TestTetheringEventCallback tetherEventCallback = 436 mCtsTetheringUtils.registerTetheringEventCallback(); 437 438 boolean previousWifiEnabledState = false; 439 440 try { 441 tetherEventCallback.assumeWifiTetheringSupported(mContext); 442 tetherEventCallback.expectNoTetheringActive(); 443 444 previousWifiEnabledState = mWm.isWifiEnabled(); 445 if (previousWifiEnabledState) { 446 mCtsNetUtils.ensureWifiDisconnected(null); 447 } 448 449 final TestNetworkCallback networkCallback = new TestNetworkCallback(); 450 Network activeNetwork = null; 451 try { 452 mCm.registerDefaultNetworkCallback(networkCallback); 453 activeNetwork = networkCallback.waitForAvailable(); 454 } finally { 455 mCm.unregisterNetworkCallback(networkCallback); 456 } 457 458 assertNotNull("No active network. Please ensure the device has working mobile data.", 459 activeNetwork); 460 final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork); 461 462 // If active nework is ETHERNET, tethering may not use cell network as upstream. 463 assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET)); 464 465 assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR)); 466 467 mCtsTetheringUtils.startWifiTethering(tetherEventCallback); 468 469 final int expectedCap = isTetheringApnRequired() 470 ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET; 471 final Network network = tetherEventCallback.getCurrentValidUpstream(); 472 final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network); 473 assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR)); 474 assertTrue(netCap.hasCapability(expectedCap)); 475 476 mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); 477 } finally { 478 mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); 479 if (previousWifiEnabledState) { 480 mCtsNetUtils.connectToWifi(); 481 } 482 } 483 } 484 } 485