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