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