• 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.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