• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Manifest.permission.WRITE_SETTINGS;
21 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
24 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
25 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
26 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
27 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
28 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
29 import static android.net.TetheringManager.TETHERING_ETHERNET;
30 import static android.net.TetheringManager.TETHERING_NCM;
31 import static android.net.TetheringManager.TETHERING_USB;
32 import static android.net.TetheringManager.TETHERING_VIRTUAL;
33 import static android.net.TetheringManager.TETHERING_WIFI;
34 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
35 import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST;
36 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
37 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
38 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
39 import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST;
40 import static android.net.cts.util.CtsTetheringUtils.isAnyIfaceMatch;
41 import static android.os.Process.INVALID_UID;
42 
43 import static com.android.testutils.TestPermissionUtil.runAsShell;
44 
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertFalse;
47 import static org.junit.Assert.assertNotEquals;
48 import static org.junit.Assert.assertNotNull;
49 import static org.junit.Assert.assertNull;
50 import static org.junit.Assert.assertThrows;
51 import static org.junit.Assert.assertTrue;
52 import static org.junit.Assert.fail;
53 import static org.junit.Assume.assumeFalse;
54 import static org.junit.Assume.assumeTrue;
55 
56 import android.content.BroadcastReceiver;
57 import android.content.Context;
58 import android.content.Intent;
59 import android.content.IntentFilter;
60 import android.content.pm.PackageManager;
61 import android.net.ConnectivityManager;
62 import android.net.LinkAddress;
63 import android.net.Network;
64 import android.net.NetworkCapabilities;
65 import android.net.TetheringInterface;
66 import android.net.TetheringManager;
67 import android.net.TetheringManager.OnTetheringEntitlementResultListener;
68 import android.net.TetheringManager.TetheringInterfaceRegexps;
69 import android.net.TetheringManager.TetheringRequest;
70 import android.net.cts.util.CtsNetUtils;
71 import android.net.cts.util.CtsNetUtils.TestNetworkCallback;
72 import android.net.cts.util.CtsTetheringUtils;
73 import android.net.cts.util.CtsTetheringUtils.StartTetheringCallback;
74 import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
75 import android.net.wifi.SoftApConfiguration;
76 import android.net.wifi.WifiManager;
77 import android.net.wifi.WifiSsid;
78 import android.os.Bundle;
79 import android.os.PersistableBundle;
80 import android.os.ResultReceiver;
81 import android.telephony.CarrierConfigManager;
82 import android.telephony.SubscriptionManager;
83 import android.telephony.TelephonyManager;
84 
85 import androidx.annotation.NonNull;
86 import androidx.test.InstrumentationRegistry;
87 import androidx.test.runner.AndroidJUnit4;
88 
89 import com.android.modules.utils.build.SdkLevel;
90 import com.android.testutils.ParcelUtils;
91 import com.android.testutils.com.android.testutils.CarrierConfigRule;
92 
93 import org.junit.After;
94 import org.junit.Before;
95 import org.junit.Rule;
96 import org.junit.Test;
97 import org.junit.runner.RunWith;
98 
99 import java.nio.charset.StandardCharsets;
100 import java.util.ArrayList;
101 import java.util.Arrays;
102 import java.util.List;
103 import java.util.concurrent.CompletableFuture;
104 import java.util.concurrent.LinkedBlockingQueue;
105 import java.util.concurrent.TimeUnit;
106 import java.util.function.Consumer;
107 
108 @RunWith(AndroidJUnit4.class)
109 public class TetheringManagerTest {
110     @Rule
111     public final CarrierConfigRule mCarrierConfigRule = new CarrierConfigRule();
112 
113     private Context mContext;
114 
115     private ConnectivityManager mCm;
116     private TetheringManager mTM;
117     private WifiManager mWm;
118     private PackageManager mPm;
119 
120     private TetherChangeReceiver mTetherChangeReceiver;
121     private CtsNetUtils mCtsNetUtils;
122     private CtsTetheringUtils mCtsTetheringUtils;
123 
124     private static final int DEFAULT_TIMEOUT_MS = 60_000;
125 
126     @Before
setUp()127     public void setUp() throws Exception {
128         mContext = InstrumentationRegistry.getContext();
129         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
130         mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
131         mWm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
132         mPm = mContext.getPackageManager();
133         mCtsNetUtils = new CtsNetUtils(mContext);
134         mCtsTetheringUtils = new CtsTetheringUtils(mContext);
135         mTetherChangeReceiver = new TetherChangeReceiver();
136         final IntentFilter filter = new IntentFilter(
137                 TetheringManager.ACTION_TETHER_STATE_CHANGED);
138         final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
139         if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
140     }
141 
142     @After
tearDown()143     public void tearDown() throws Exception {
144         mCtsTetheringUtils.stopAllTethering();
145         mContext.unregisterReceiver(mTetherChangeReceiver);
146     }
147 
148     private class TetherChangeReceiver extends BroadcastReceiver {
149         private class TetherState {
150             final ArrayList<String> mAvailable;
151             final ArrayList<String> mActive;
152             final ArrayList<String> mErrored;
153 
TetherState(Intent intent)154             TetherState(Intent intent) {
155                 mAvailable = intent.getStringArrayListExtra(
156                         TetheringManager.EXTRA_AVAILABLE_TETHER);
157                 mActive = intent.getStringArrayListExtra(
158                         TetheringManager.EXTRA_ACTIVE_TETHER);
159                 mErrored = intent.getStringArrayListExtra(
160                         TetheringManager.EXTRA_ERRORED_TETHER);
161             }
162         }
163 
164         @Override
onReceive(Context content, Intent intent)165         public void onReceive(Context content, Intent intent) {
166             String action = intent.getAction();
167             if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) {
168                 mResult.add(new TetherState(intent));
169             }
170         }
171 
172         public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
173 
174         // Expects that tethering reaches the desired state.
175         // - If active is true, expects that tethering is enabled on at least one interface
176         //   matching ifaceRegexs.
177         // - If active is false, expects that tethering is disabled on all the interfaces matching
178         //   ifaceRegexs.
179         // Fails if any interface matching ifaceRegexs becomes errored.
expectTethering(final boolean active, final String[] ifaceRegexs)180         public void expectTethering(final boolean active, final String[] ifaceRegexs) {
181             while (true) {
182                 final TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS, ifaceRegexs);
183                 assertNotNull("Did not receive expected state change, active: " + active, state);
184 
185                 if (isIfaceActive(ifaceRegexs, state) == active) return;
186             }
187         }
188 
pollAndAssertNoError(final int timeout, final String[] ifaceRegexs)189         private TetherState pollAndAssertNoError(final int timeout, final String[] ifaceRegexs) {
190             final TetherState state = pollTetherState(timeout);
191             assertNoErroredIfaces(state, ifaceRegexs);
192             return state;
193         }
194 
pollTetherState(final int timeout)195         private TetherState pollTetherState(final int timeout) {
196             try {
197                 return mResult.poll(timeout, TimeUnit.MILLISECONDS);
198             } catch (InterruptedException e) {
199                 fail("No result after " + timeout + " ms");
200                 return null;
201             }
202         }
203 
isIfaceActive(final String[] ifaceRegexs, final TetherState state)204         private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) {
205             return isAnyIfaceMatch(ifaceRegexs, state.mActive);
206         }
207 
assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs)208         private void assertNoErroredIfaces(final TetherState state, final String[] ifaceRegexs) {
209             if (state == null || state.mErrored == null) return;
210 
211             if (isAnyIfaceMatch(ifaceRegexs, state.mErrored)) {
212                 fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray()));
213             }
214         }
215     }
216 
217     @Test
testStartTetheringWithStateChangeBroadcast()218     public void testStartTetheringWithStateChangeBroadcast() throws Exception {
219         final TestTetheringEventCallback tetherEventCallback =
220                 mCtsTetheringUtils.registerTetheringEventCallback();
221         try {
222             tetherEventCallback.assumeWifiTetheringSupported(mContext);
223             tetherEventCallback.expectNoTetheringActive();
224 
225             final String[] wifiRegexs = mTM.getTetherableWifiRegexs();
226             mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
227 
228             mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs);
229 
230             mCtsTetheringUtils.stopWifiTethering(tetherEventCallback);
231             mTetherChangeReceiver.expectTethering(false /* active */, wifiRegexs);
232         } finally {
233             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
234         }
235 
236     }
237 
238     @Test
testStartTetheringDuplicateRequestRejected()239     public void testStartTetheringDuplicateRequestRejected() throws Exception {
240         assumeTrue(SdkLevel.isAtLeastB());
241         final TestTetheringEventCallback tetherEventCallback =
242                 mCtsTetheringUtils.registerTetheringEventCallback();
243         try {
244             tetherEventCallback.assumeWifiTetheringSupported(mContext);
245             tetherEventCallback.expectNoTetheringActive();
246 
247             final String[] wifiRegexs = mTM.getTetherableWifiRegexs();
248             mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
249             mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs);
250 
251             final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
252             runAsShell(TETHER_PRIVILEGED, () -> {
253                 mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
254                         c -> c.run() /* executor */, startTetheringCallback);
255                 startTetheringCallback.expectTetheringFailed(TETHER_ERROR_DUPLICATE_REQUEST);
256             });
257         } finally {
258             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
259         }
260     }
261 
createSoftApConfiguration(@onNull String ssid)262     private SoftApConfiguration createSoftApConfiguration(@NonNull String ssid) {
263         SoftApConfiguration config;
264         if (SdkLevel.isAtLeastT()) {
265             config = new SoftApConfiguration.Builder()
266                     .setWifiSsid(WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)))
267                     .build();
268         } else {
269             config = new SoftApConfiguration.Builder()
270                     .setSsid(ssid)
271                     .build();
272         }
273         return config;
274     }
275 
276     @Test
testTetheringRequest()277     public void testTetheringRequest() {
278         SoftApConfiguration softApConfiguration = createSoftApConfiguration("SSID");
279         final TetheringRequest tr = new TetheringRequest.Builder(TETHERING_WIFI)
280                 .setSoftApConfiguration(softApConfiguration)
281                 .build();
282         assertEquals(TETHERING_WIFI, tr.getTetheringType());
283         assertNull(tr.getLocalIpv4Address());
284         assertNull(tr.getClientStaticIpv4Address());
285         assertFalse(tr.isExemptFromEntitlementCheck());
286         assertTrue(tr.getShouldShowEntitlementUi());
287         assertEquals(CONNECTIVITY_SCOPE_GLOBAL, tr.getConnectivityScope());
288         assertEquals(softApConfiguration, tr.getSoftApConfiguration());
289         assertEquals(INVALID_UID, tr.getUid());
290         assertNull(tr.getPackageName());
291         assertEquals(tr.toString(), "TetheringRequest[ "
292                 + "TETHERING_WIFI, "
293                 + "showProvisioningUi, "
294                 + "CONNECTIVITY_SCOPE_GLOBAL, "
295                 + "softApConfig=" + softApConfiguration.toString()
296                 + " ]");
297 
298         final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
299         final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
300         final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB)
301                 .setStaticIpv4Addresses(localAddr, clientAddr)
302                 .setExemptFromEntitlementCheck(true)
303                 .setShouldShowEntitlementUi(false)
304                 .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL)
305                 .build();
306         int uid = 1000;
307         String packageName = "package";
308         tr2.setUid(uid);
309         tr2.setPackageName(packageName);
310 
311         assertEquals(localAddr, tr2.getLocalIpv4Address());
312         assertEquals(clientAddr, tr2.getClientStaticIpv4Address());
313         assertEquals(TETHERING_USB, tr2.getTetheringType());
314         assertTrue(tr2.isExemptFromEntitlementCheck());
315         assertFalse(tr2.getShouldShowEntitlementUi());
316         assertEquals(CONNECTIVITY_SCOPE_LOCAL, tr2.getConnectivityScope());
317         assertNull(tr2.getSoftApConfiguration());
318         assertEquals(uid, tr2.getUid());
319         assertEquals(packageName, tr2.getPackageName());
320         assertEquals(tr2.toString(), "TetheringRequest[ "
321                 + "TETHERING_USB, "
322                 + "localIpv4Address=" + localAddr + ", "
323                 + "staticClientAddress=" + clientAddr + ", "
324                 + "exemptFromEntitlementCheck, "
325                 + "CONNECTIVITY_SCOPE_LOCAL, "
326                 + "uid=1000, "
327                 + "packageName=package"
328                 + " ]");
329 
330         final TetheringRequest tr3 = new TetheringRequest.Builder(TETHERING_USB)
331                 .setStaticIpv4Addresses(localAddr, clientAddr)
332                 .setExemptFromEntitlementCheck(true)
333                 .setShouldShowEntitlementUi(false)
334                 .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL)
335                 .build();
336         tr3.setUid(uid);
337         tr3.setPackageName(packageName);
338         assertEquals(tr2, tr3);
339 
340         final String interfaceName = "test_iface";
341         final TetheringRequest tr4 = new TetheringRequest.Builder(TETHERING_VIRTUAL)
342                 .setInterfaceName(interfaceName)
343                 .setConnectivityScope(CONNECTIVITY_SCOPE_GLOBAL).build();
344         assertEquals(interfaceName, tr4.getInterfaceName());
345         assertEquals(CONNECTIVITY_SCOPE_GLOBAL, tr4.getConnectivityScope());
346     }
347 
348     @Test
testTetheringRequestSetSoftApConfigurationFailsWhenNotWifi()349     public void testTetheringRequestSetSoftApConfigurationFailsWhenNotWifi() {
350         final SoftApConfiguration softApConfiguration = createSoftApConfiguration("SSID");
351         for (int type : List.of(TETHERING_USB, TETHERING_BLUETOOTH, TETHERING_WIFI_P2P,
352                 TETHERING_NCM, TETHERING_ETHERNET)) {
353             try {
354                 new TetheringRequest.Builder(type).setSoftApConfiguration(softApConfiguration);
355                 fail("Was able to set SoftApConfiguration for tethering type " + type);
356             } catch (IllegalArgumentException e) {
357                 // Success
358             }
359         }
360     }
361 
362     @Test
testTetheringRequestSetInterfaceNameFailsExceptTetheringVirtual()363     public void testTetheringRequestSetInterfaceNameFailsExceptTetheringVirtual() {
364         for (int type : List.of(TETHERING_USB, TETHERING_BLUETOOTH, TETHERING_NCM,
365                 TETHERING_ETHERNET)) {
366             try {
367                 new TetheringRequest.Builder(type).setInterfaceName("test_iface");
368                 fail("Was able to set interface name for tethering type " + type);
369             } catch (IllegalArgumentException e) {
370                 // Success
371             }
372         }
373     }
374 
375     @Test
testTetheringRequestParcelable()376     public void testTetheringRequestParcelable() {
377         final SoftApConfiguration softApConfiguration = createSoftApConfiguration("SSID");
378         final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
379         final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
380         final TetheringRequest withApConfig = new TetheringRequest.Builder(TETHERING_WIFI)
381                 .setSoftApConfiguration(softApConfiguration)
382                 .setStaticIpv4Addresses(localAddr, clientAddr)
383                 .setExemptFromEntitlementCheck(true)
384                 .setShouldShowEntitlementUi(false).build();
385         final TetheringRequest withoutApConfig = new TetheringRequest.Builder(TETHERING_WIFI)
386                 .setStaticIpv4Addresses(localAddr, clientAddr)
387                 .setExemptFromEntitlementCheck(true)
388                 .setShouldShowEntitlementUi(false).build();
389         assertEquals(withApConfig, ParcelUtils.parcelingRoundTrip(withApConfig));
390         assertEquals(withoutApConfig, ParcelUtils.parcelingRoundTrip(withoutApConfig));
391         assertNotEquals(withApConfig, ParcelUtils.parcelingRoundTrip(withoutApConfig));
392         assertNotEquals(withoutApConfig, ParcelUtils.parcelingRoundTrip(withApConfig));
393 
394         final TetheringRequest withIfaceName = new TetheringRequest.Builder(TETHERING_VIRTUAL)
395                 .setInterfaceName("test_iface").build();
396         assertEquals(withIfaceName, ParcelUtils.parcelingRoundTrip(withIfaceName));
397     }
398 
399     @Test
testRegisterTetheringEventCallback()400     public void testRegisterTetheringEventCallback() throws Exception {
401         final TestTetheringEventCallback tetherEventCallback =
402                 mCtsTetheringUtils.registerTetheringEventCallback();
403 
404         try {
405             tetherEventCallback.assumeWifiTetheringSupported(mContext);
406             tetherEventCallback.expectNoTetheringActive();
407 
408             SoftApConfiguration softApConfig = SdkLevel.isAtLeastB()
409                     ? createSoftApConfiguration("SSID") : null;
410             final TetheringInterface tetheredIface =
411                     mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
412 
413             assertNotNull(tetheredIface);
414             if  (SdkLevel.isAtLeastB()) {
415                 assertEquals(softApConfig, tetheredIface.getSoftApConfiguration());
416             }
417 
418             mCtsTetheringUtils.stopWifiTethering(tetherEventCallback);
419 
420             if (!SdkLevel.isAtLeastB()) {
421                 final String wifiTetheringIface = tetheredIface.getInterface();
422                 try {
423                     final int ret = runAsShell(TETHER_PRIVILEGED,
424                             () -> mTM.tether(wifiTetheringIface));
425                     // There is no guarantee that the wifi interface will be available after
426                     // disabling the hotspot, so don't fail the test if the call to tether() fails.
427                     if (ret == TETHER_ERROR_NO_ERROR) {
428                         // If calling #tether successful, there is a callback to tell the result of
429                         // tethering setup.
430                         tetherEventCallback.expectErrorOrTethered(
431                                 new TetheringInterface(TETHERING_WIFI, wifiTetheringIface));
432                     }
433                 } finally {
434                     runAsShell(TETHER_PRIVILEGED, () -> mTM.untether(wifiTetheringIface));
435                 }
436             }
437         } finally {
438             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
439         }
440     }
441 
442     @Test
testGetTetherableInterfaceRegexps()443     public void testGetTetherableInterfaceRegexps() {
444         final TestTetheringEventCallback tetherEventCallback =
445                 mCtsTetheringUtils.registerTetheringEventCallback();
446         tetherEventCallback.assumeTetheringSupported();
447 
448         final TetheringInterfaceRegexps tetherableRegexs =
449                 tetherEventCallback.getTetheringInterfaceRegexps();
450         final List<String> wifiRegexs = tetherableRegexs.getTetherableWifiRegexs();
451         final List<String> usbRegexs = tetherableRegexs.getTetherableUsbRegexs();
452         final List<String> btRegexs = tetherableRegexs.getTetherableBluetoothRegexs();
453 
454         assertEquals(wifiRegexs, Arrays.asList(mTM.getTetherableWifiRegexs()));
455         assertEquals(usbRegexs, Arrays.asList(mTM.getTetherableUsbRegexs()));
456         assertEquals(btRegexs, Arrays.asList(mTM.getTetherableBluetoothRegexs()));
457 
458         //Verify that any regex name should only contain in one array.
459         wifiRegexs.forEach(s -> assertFalse(usbRegexs.contains(s)));
460         wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s)));
461         usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s)));
462 
463         mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
464     }
465 
466     @Test
testStopAllTethering()467     public void testStopAllTethering() throws Exception {
468         final TestTetheringEventCallback tetherEventCallback =
469                 mCtsTetheringUtils.registerTetheringEventCallback();
470         try {
471             tetherEventCallback.assumeWifiTetheringSupported(mContext);
472 
473             // TODO: start ethernet tethering here when TetheringManagerTest is moved to
474             // TetheringIntegrationTest.
475 
476             mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
477 
478             mCtsTetheringUtils.stopAllTethering();
479             tetherEventCallback.expectNoTetheringActive();
480         } finally {
481             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
482         }
483     }
484 
485     @Test
testStopTetheringRequestNoMatchFailure()486     public void testStopTetheringRequestNoMatchFailure() throws Exception {
487         assumeTrue(SdkLevel.isAtLeastB());
488         final TestTetheringEventCallback tetherEventCallback =
489                 mCtsTetheringUtils.registerTetheringEventCallback();
490         try {
491             tetherEventCallback.assumeWifiTetheringSupported(mContext);
492             tetherEventCallback.expectNoTetheringActive();
493 
494             final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
495             mTM.startTethering(new TetheringRequest.Builder(TETHERING_VIRTUAL).build(),
496                     c -> c.run(), startTetheringCallback);
497 
498             // Stopping a non-matching request should have no effect
499             TetheringRequest nonMatchingRequest = new TetheringRequest.Builder(TETHERING_VIRTUAL)
500                     .setInterfaceName("iface")
501                     .build();
502             mCtsTetheringUtils.stopTethering(nonMatchingRequest, false /* success */);
503         } finally {
504             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
505         }
506     }
507 
508     @Test
testStopTetheringRequestMatchSuccess()509     public void testStopTetheringRequestMatchSuccess() throws Exception {
510         assumeTrue(SdkLevel.isAtLeastB());
511         final TestTetheringEventCallback tetherEventCallback =
512                 mCtsTetheringUtils.registerTetheringEventCallback();
513         try {
514             tetherEventCallback.assumeWifiTetheringSupported(mContext);
515             tetherEventCallback.expectNoTetheringActive();
516 
517             SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
518                     .setWifiSsid(WifiSsid.fromBytes("This is one config"
519                             .getBytes(StandardCharsets.UTF_8))).build();
520             mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
521 
522             // Stopping the active request should stop tethering.
523             TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
524                     .setSoftApConfiguration(softApConfig)
525                     .build();
526             mCtsTetheringUtils.stopTethering(request, true /* success */);
527             tetherEventCallback.expectNoTetheringActive();
528         } finally {
529             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
530         }
531     }
532 
533     @Test
testStopTetheringRequestFuzzyMatchSuccess()534     public void testStopTetheringRequestFuzzyMatchSuccess() throws Exception {
535         assumeTrue(SdkLevel.isAtLeastB());
536         final TestTetheringEventCallback tetherEventCallback =
537                 mCtsTetheringUtils.registerTetheringEventCallback();
538         try {
539             tetherEventCallback.assumeWifiTetheringSupported(mContext);
540             tetherEventCallback.expectNoTetheringActive();
541 
542             SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
543                     .setWifiSsid(WifiSsid.fromBytes("This is one config"
544                             .getBytes(StandardCharsets.UTF_8))).build();
545             mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
546 
547             // Stopping with a fuzzy matching request should stop tethering.
548             final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
549             final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
550             TetheringRequest fuzzyMatchingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
551                     .setSoftApConfiguration(softApConfig)
552                     .setShouldShowEntitlementUi(true)
553                     .setStaticIpv4Addresses(localAddr, clientAddr)
554                     .build();
555             mCtsTetheringUtils.stopTethering(fuzzyMatchingRequest, true /* success */);
556             tetherEventCallback.expectNoTetheringActive();
557         } finally {
558             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
559         }
560     }
561 
562     @Test
testStartTetheringNoPermission()563     public void testStartTetheringNoPermission() throws Exception {
564         final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
565 
566         // No permission
567         mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
568                 c -> c.run() /* executor */, startTetheringCallback);
569         startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
570 
571         // WRITE_SETTINGS not sufficient
572         if (SdkLevel.isAtLeastB()) {
573             runAsShell(WRITE_SETTINGS, () -> {
574                 mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
575                         c -> c.run() /* executor */, startTetheringCallback);
576                 startTetheringCallback.expectTetheringFailed(
577                         TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
578             });
579         }
580     }
581 
582     private class EntitlementResultListener implements OnTetheringEntitlementResultListener {
583         private final CompletableFuture<Integer> future = new CompletableFuture<>();
584 
585         @Override
onTetheringEntitlementResult(int result)586         public void onTetheringEntitlementResult(int result) {
587             future.complete(result);
588         }
589 
get(long timeout, TimeUnit unit)590         public int get(long timeout, TimeUnit unit) throws Exception {
591             return future.get(timeout, unit);
592         }
593 
594     }
595 
assertEntitlementResult(final Consumer<EntitlementResultListener> functor, final int expect)596     private void assertEntitlementResult(final Consumer<EntitlementResultListener> functor,
597             final int expect) throws Exception {
598         runAsShell(TETHER_PRIVILEGED, () -> {
599             final EntitlementResultListener listener = new EntitlementResultListener();
600             functor.accept(listener);
601 
602             assertEquals(expect, listener.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
603         });
604     }
605 
isTetheringSupported()606     private boolean isTetheringSupported() {
607         return runAsShell(TETHER_PRIVILEGED, () -> mTM.isTetheringSupported());
608     }
609 
610     @Test
testRequestLatestEntitlementResult()611     public void testRequestLatestEntitlementResult() throws Exception {
612         assumeTrue(isTetheringSupported());
613         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
614         // Verify that requestLatestTetheringEntitlementResult() can get entitlement
615         // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener.
616         assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
617                 TETHERING_WIFI_P2P, false, c -> c.run(), listener),
618                 TETHER_ERROR_ENTITLEMENT_UNKNOWN);
619 
620         // Verify that requestLatestTetheringEntitlementResult() can get entitlement
621         // result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via receiver.
622         assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
623                 TETHERING_WIFI_P2P,
624                 new ResultReceiver(null /* handler */) {
625                     @Override
626                     public void onReceiveResult(int resultCode, Bundle resultData) {
627                         listener.onTetheringEntitlementResult(resultCode);
628                     }
629                 }, false),
630                 TETHER_ERROR_ENTITLEMENT_UNKNOWN);
631 
632         // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available.
633         assumeTrue(mTM.getTetherableWifiRegexs().length > 0);
634 
635         // Verify that null listener will cause IllegalArgumentException.
636         try {
637             mTM.requestLatestTetheringEntitlementResult(
638                     TETHERING_WIFI, false, c -> c.run(), null);
639         } catch (IllegalArgumentException expect) { }
640 
641         // Override carrier config to ignore entitlement check.
642         final PersistableBundle bundle = new PersistableBundle();
643         bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false);
644         mCarrierConfigRule.addConfigOverrides(
645                 SubscriptionManager.getDefaultSubscriptionId(), bundle);
646 
647         // Verify that requestLatestTetheringEntitlementResult() can get entitlement
648         // result TETHER_ERROR_NO_ERROR due to provisioning bypassed.
649         assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
650                 TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR);
651     }
652 
isTetheringApnRequired()653     private boolean isTetheringApnRequired() {
654         final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
655         return runAsShell(MODIFY_PHONE_STATE, () -> tm.isTetheringApnRequired());
656 
657     }
658 
659     @Test
testTetheringUpstream()660     public void testTetheringUpstream() throws Exception {
661         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
662         final TestTetheringEventCallback tetherEventCallback =
663                 mCtsTetheringUtils.registerTetheringEventCallback();
664 
665         boolean previousWifiEnabledState = false;
666 
667         try {
668             tetherEventCallback.assumeWifiTetheringSupported(mContext);
669             tetherEventCallback.expectNoTetheringActive();
670 
671             previousWifiEnabledState = mWm.isWifiEnabled();
672             if (previousWifiEnabledState) {
673                 mCtsNetUtils.ensureWifiDisconnected(null);
674             }
675 
676             final TestNetworkCallback networkCallback = new TestNetworkCallback();
677             Network activeNetwork = null;
678             try {
679                 mCm.registerDefaultNetworkCallback(networkCallback);
680                 activeNetwork = networkCallback.waitForAvailable();
681             } finally {
682                 mCm.unregisterNetworkCallback(networkCallback);
683             }
684 
685             assertNotNull("No active network. Please ensure the device has working mobile data.",
686                     activeNetwork);
687             final NetworkCapabilities activeNetCap = mCm.getNetworkCapabilities(activeNetwork);
688 
689             // If active nework is ETHERNET, tethering may not use cell network as upstream.
690             assumeFalse(activeNetCap.hasTransport(TRANSPORT_ETHERNET));
691 
692             assertTrue(activeNetCap.hasTransport(TRANSPORT_CELLULAR));
693 
694             mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
695 
696             final int expectedCap = isTetheringApnRequired()
697                     ? NET_CAPABILITY_DUN : NET_CAPABILITY_INTERNET;
698             final Network network = tetherEventCallback.getCurrentValidUpstream();
699             final NetworkCapabilities netCap = mCm.getNetworkCapabilities(network);
700             assertTrue(netCap.hasTransport(TRANSPORT_CELLULAR));
701             assertTrue(netCap.hasCapability(expectedCap));
702 
703             mCtsTetheringUtils.stopWifiTethering(tetherEventCallback);
704         } finally {
705             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
706             if (previousWifiEnabledState) {
707                 mCtsNetUtils.connectToWifi();
708             }
709         }
710     }
711 
712     @Test
testLegacyTetherApisThrowUnsupportedOperationExceptionAfterV()713     public void testLegacyTetherApisThrowUnsupportedOperationExceptionAfterV() {
714         assumeTrue(SdkLevel.isAtLeastB());
715         assertThrows(UnsupportedOperationException.class, () -> mTM.tether("iface"));
716         assertThrows(UnsupportedOperationException.class, () -> mTM.untether("iface"));
717     }
718 
719     @Test
testCarrierPrivilegedIsTetheringSupported()720     public void testCarrierPrivilegedIsTetheringSupported() throws Exception {
721         assumeTrue(SdkLevel.isAtLeastB());
722         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
723         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
724         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
725         final TestTetheringEventCallback tetherEventCallback =
726                 mCtsTetheringUtils.registerTetheringEventCallback();
727         try {
728             tetherEventCallback.assumeWifiTetheringSupported(mContext);
729             tetherEventCallback.expectNoTetheringActive();
730 
731             assertTrue(mTM.isTetheringSupported());
732         } finally {
733             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
734         }
735     }
736 
737     @Test
testCarrierPrivilegedStartTetheringNonWifiFails()738     public void testCarrierPrivilegedStartTetheringNonWifiFails() throws Exception {
739         assumeTrue(SdkLevel.isAtLeastB());
740         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
741         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
742         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
743         final TestTetheringEventCallback tetherEventCallback =
744                 mCtsTetheringUtils.registerTetheringEventCallback();
745         try {
746             tetherEventCallback.assumeWifiTetheringSupported(mContext);
747             tetherEventCallback.expectNoTetheringActive();
748             StartTetheringCallback callback = new StartTetheringCallback();
749             TetheringRequest request = new TetheringRequest.Builder(TETHERING_USB).build();
750 
751             mTM.startTethering(request, Runnable::run, callback);
752 
753             callback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
754         } finally {
755             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
756         }
757     }
758 
759     @Test
testCarrierPrivilegedStartTetheringWifiWithoutConfigFails()760     public void testCarrierPrivilegedStartTetheringWifiWithoutConfigFails() throws Exception {
761         assumeTrue(SdkLevel.isAtLeastB());
762         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
763         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
764         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
765         final TestTetheringEventCallback tetherEventCallback =
766                 mCtsTetheringUtils.registerTetheringEventCallback();
767         try {
768             tetherEventCallback.assumeWifiTetheringSupported(mContext);
769             tetherEventCallback.expectNoTetheringActive();
770             StartTetheringCallback callback = new StartTetheringCallback();
771             TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
772 
773             mTM.startTethering(request, Runnable::run, callback);
774 
775             callback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
776         } finally {
777             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
778         }
779     }
780 
781     @Test
testCarrierPrivilegedStartTetheringWifiWithConfigSucceeds()782     public void testCarrierPrivilegedStartTetheringWifiWithConfigSucceeds() throws Exception {
783         assumeTrue(SdkLevel.isAtLeastB());
784         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
785         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
786         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
787         final TestTetheringEventCallback tetherEventCallback =
788                 mCtsTetheringUtils.registerTetheringEventCallback();
789         try {
790             tetherEventCallback.assumeWifiTetheringSupported(mContext);
791             tetherEventCallback.expectNoTetheringActive();
792             SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
793 
794             mCtsTetheringUtils.startWifiTetheringNoPermissions(tetherEventCallback, softApConfig);
795         } finally {
796             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
797         }
798     }
799 
800     @Test
testCarrierPrivilegedStopTetheringNonWifiFails()801     public void testCarrierPrivilegedStopTetheringNonWifiFails() throws Exception {
802         assumeTrue(SdkLevel.isAtLeastB());
803         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
804         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
805         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
806         final TestTetheringEventCallback tetherEventCallback =
807                 mCtsTetheringUtils.registerTetheringEventCallback();
808         try {
809             tetherEventCallback.assumeWifiTetheringSupported(mContext);
810             tetherEventCallback.expectNoTetheringActive();
811             TetheringRequest request = new TetheringRequest.Builder(TETHERING_USB).build();
812             CtsTetheringUtils.StopTetheringCallback
813                     callback = new CtsTetheringUtils.StopTetheringCallback();
814 
815             mTM.stopTethering(request, Runnable::run, callback);
816 
817             callback.expectStopTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
818         } finally {
819             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
820         }
821     }
822 
823     @Test
testCarrierPrivilegedStopTetheringWifiWithoutConfigFails()824     public void testCarrierPrivilegedStopTetheringWifiWithoutConfigFails() throws Exception {
825         assumeTrue(SdkLevel.isAtLeastB());
826         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
827         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
828         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
829         final TestTetheringEventCallback tetherEventCallback =
830                 mCtsTetheringUtils.registerTetheringEventCallback();
831         try {
832             tetherEventCallback.assumeWifiTetheringSupported(mContext);
833             tetherEventCallback.expectNoTetheringActive();
834             TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
835             CtsTetheringUtils.StopTetheringCallback
836                     callback = new CtsTetheringUtils.StopTetheringCallback();
837 
838             mTM.stopTethering(request, Runnable::run, callback);
839 
840             callback.expectStopTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
841         } finally {
842             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
843         }
844     }
845 
846     @Test
testCarrierPrivilegedStopTetheringWifiWithConfigButNoActiveRequestFails()847     public void testCarrierPrivilegedStopTetheringWifiWithConfigButNoActiveRequestFails()
848             throws Exception {
849         assumeTrue(SdkLevel.isAtLeastB());
850         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
851         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
852         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
853         final TestTetheringEventCallback tetherEventCallback =
854                 mCtsTetheringUtils.registerTetheringEventCallback();
855         try {
856             tetherEventCallback.assumeWifiTetheringSupported(mContext);
857             tetherEventCallback.expectNoTetheringActive();
858             SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
859             TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
860                     .setSoftApConfiguration(softApConfig)
861                     .build();
862             CtsTetheringUtils.StopTetheringCallback
863                     callback = new CtsTetheringUtils.StopTetheringCallback();
864 
865             mTM.stopTethering(request, Runnable::run, callback);
866 
867             callback.expectStopTetheringFailed(TETHER_ERROR_UNKNOWN_REQUEST);
868         } finally {
869             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
870         }
871     }
872 
873     @Test
testCarrierPrivilegedStopTetheringWifiWithConfigSucceeds()874     public void testCarrierPrivilegedStopTetheringWifiWithConfigSucceeds() throws Exception {
875         assumeTrue(SdkLevel.isAtLeastB());
876         assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
877         int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
878         mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
879         final TestTetheringEventCallback tetherEventCallback =
880                 mCtsTetheringUtils.registerTetheringEventCallback();
881         try {
882             tetherEventCallback.assumeWifiTetheringSupported(mContext);
883             tetherEventCallback.expectNoTetheringActive();
884             SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
885             mCtsTetheringUtils.startWifiTetheringNoPermissions(tetherEventCallback, softApConfig);
886             TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
887                     .setSoftApConfiguration(softApConfig)
888                     .build();
889             CtsTetheringUtils.StopTetheringCallback
890                     callback = new CtsTetheringUtils.StopTetheringCallback();
891 
892             mTM.stopTethering(request, Runnable::run, callback);
893 
894             callback.verifyStopTetheringSucceeded();
895         } finally {
896             mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
897         }
898     }
899 }
900