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