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