blob: 099cfd457160e88365ef4ba2510d3da8df7f7c9e [file] [log] [blame]
Christopher Wiley497c1472016-10-11 13:26:03 -07001/*
2 * Copyright (C) 2016 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
17package com.android.server.connectivity;
18
Erik Klinec438e302017-07-04 22:02:49 +090019import static android.hardware.usb.UsbManager.USB_CONFIGURED;
20import static android.hardware.usb.UsbManager.USB_CONNECTED;
21import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
22import static android.net.ConnectivityManager.TETHERING_WIFI;
23import static android.net.ConnectivityManager.TETHERING_USB;
Erik Kline2efb8272017-05-31 15:53:53 +090024import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
25import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
26import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
27import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
28import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
29import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
Erik Klineea9cc482017-03-10 19:35:34 +090030import static org.junit.Assert.assertEquals;
Christopher Wiley497c1472016-10-11 13:26:03 -070031import static org.junit.Assert.assertTrue;
32import static org.mockito.Matchers.anyBoolean;
Erik Klineea9cc482017-03-10 19:35:34 +090033import static org.mockito.Matchers.anyInt;
34import static org.mockito.Matchers.anyString;
Christopher Wiley497c1472016-10-11 13:26:03 -070035import static org.mockito.Matchers.eq;
Erik Kline1fdc2e22017-05-08 17:56:35 +090036import static org.mockito.Mockito.any;
Erik Klineea9cc482017-03-10 19:35:34 +090037import static org.mockito.Mockito.atLeastOnce;
Erik Kline1fdc2e22017-05-08 17:56:35 +090038import static org.mockito.Mockito.doThrow;
Erik Klineea9cc482017-03-10 19:35:34 +090039import static org.mockito.Mockito.times;
40import static org.mockito.Mockito.verify;
41import static org.mockito.Mockito.verifyNoMoreInteractions;
Christopher Wiley497c1472016-10-11 13:26:03 -070042import static org.mockito.Mockito.when;
Alexandru-Andrei Rotarufa6d5c52017-07-18 16:49:22 +010043import static org.mockito.Mockito.mock;
Christopher Wiley497c1472016-10-11 13:26:03 -070044
Erik Kline8351faa2017-04-17 16:47:23 +090045import android.content.BroadcastReceiver;
Erik Kline92c4db02017-05-31 10:21:32 +090046import android.content.ContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070047import android.content.Context;
Erik Klineea9cc482017-03-10 19:35:34 +090048import android.content.ContextWrapper;
49import android.content.Intent;
Erik Kline8351faa2017-04-17 16:47:23 +090050import android.content.IntentFilter;
Erik Klinef3a08b42017-06-07 16:33:19 +090051import android.content.pm.ApplicationInfo;
Christopher Wiley497c1472016-10-11 13:26:03 -070052import android.content.res.Resources;
Erik Klineea9cc482017-03-10 19:35:34 +090053import android.hardware.usb.UsbManager;
54import android.net.ConnectivityManager;
55import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070056import android.net.INetworkPolicyManager;
57import android.net.INetworkStatsService;
Erik Klineea9cc482017-03-10 19:35:34 +090058import android.net.InterfaceConfiguration;
59import android.net.NetworkRequest;
Erik Klinef4b6e342017-04-25 19:19:59 +090060import android.net.util.SharedLog;
Erik Klineea9cc482017-03-10 19:35:34 +090061import android.net.wifi.WifiConfiguration;
62import android.net.wifi.WifiManager;
Alexandru-Andrei Rotarufa6d5c52017-07-18 16:49:22 +010063import android.os.Bundle;
Erik Klineea9cc482017-03-10 19:35:34 +090064import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070065import android.os.INetworkManagementService;
66import android.os.PersistableBundle;
Erik Kline1fdc2e22017-05-08 17:56:35 +090067import android.os.RemoteException;
Christopher Wiley497c1472016-10-11 13:26:03 -070068import android.os.test.TestLooper;
Erik Klineea9cc482017-03-10 19:35:34 +090069import android.os.UserHandle;
Alexandru-Andrei Rotarufa6d5c52017-07-18 16:49:22 +010070import android.os.UserManager;
Erik Kline92c4db02017-05-31 10:21:32 +090071import android.provider.Settings;
Christopher Wiley497c1472016-10-11 13:26:03 -070072import android.support.test.filters.SmallTest;
73import android.support.test.runner.AndroidJUnit4;
74import android.telephony.CarrierConfigManager;
Erik Kline92c4db02017-05-31 10:21:32 +090075import android.test.mock.MockContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070076
Erik Klineea9cc482017-03-10 19:35:34 +090077import com.android.internal.util.test.BroadcastInterceptingContext;
Erik Kline92c4db02017-05-31 10:21:32 +090078import com.android.internal.util.test.FakeSettingsProvider;
Erik Kline5a7c8a02017-04-30 19:36:15 +090079import com.android.server.connectivity.tethering.OffloadHardwareInterface;
80import com.android.server.connectivity.tethering.TetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090081
Erik Kline8351faa2017-04-17 16:47:23 +090082import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070083import org.junit.Before;
84import org.junit.Test;
85import org.junit.runner.RunWith;
86import org.mockito.Mock;
87import org.mockito.MockitoAnnotations;
88
Erik Kline8351faa2017-04-17 16:47:23 +090089import java.util.ArrayList;
90import java.util.Vector;
91
Christopher Wiley497c1472016-10-11 13:26:03 -070092@RunWith(AndroidJUnit4.class)
93@SmallTest
94public class TetheringTest {
95 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
96
Erik Klinef3a08b42017-06-07 16:33:19 +090097 @Mock private ApplicationInfo mApplicationInfo;
Christopher Wiley497c1472016-10-11 13:26:03 -070098 @Mock private Context mContext;
Erik Klineea9cc482017-03-10 19:35:34 +090099 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -0700100 @Mock private INetworkManagementService mNMService;
101 @Mock private INetworkStatsService mStatsService;
102 @Mock private INetworkPolicyManager mPolicyManager;
103 @Mock private MockableSystemProperties mSystemProperties;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900104 @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
Christopher Wiley497c1472016-10-11 13:26:03 -0700105 @Mock private Resources mResources;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900106 @Mock private TetheringDependencies mTetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +0900107 @Mock private UsbManager mUsbManager;
108 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -0700109 @Mock private CarrierConfigManager mCarrierConfigManager;
110
111 // Like so many Android system APIs, these cannot be mocked because it is marked final.
112 // We have to use the real versions.
113 private final PersistableBundle mCarrierConfig = new PersistableBundle();
114 private final TestLooper mLooper = new TestLooper();
Erik Klineea9cc482017-03-10 19:35:34 +0900115 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -0700116
Erik Kline8351faa2017-04-17 16:47:23 +0900117 private Vector<Intent> mIntents;
Erik Klineea9cc482017-03-10 19:35:34 +0900118 private BroadcastInterceptingContext mServiceContext;
Erik Kline92c4db02017-05-31 10:21:32 +0900119 private MockContentResolver mContentResolver;
Erik Kline8351faa2017-04-17 16:47:23 +0900120 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -0700121 private Tethering mTethering;
122
Erik Klineea9cc482017-03-10 19:35:34 +0900123 private class MockContext extends BroadcastInterceptingContext {
124 MockContext(Context base) {
125 super(base);
126 }
127
128 @Override
Erik Klinef3a08b42017-06-07 16:33:19 +0900129 public ApplicationInfo getApplicationInfo() { return mApplicationInfo; }
130
131 @Override
Erik Kline92c4db02017-05-31 10:21:32 +0900132 public ContentResolver getContentResolver() { return mContentResolver; }
133
134 @Override
135 public String getPackageName() { return "TetheringTest"; }
136
137 @Override
Erik Klineea9cc482017-03-10 19:35:34 +0900138 public Resources getResources() { return mResources; }
139
140 @Override
141 public Object getSystemService(String name) {
142 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
143 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
Erik Klinec438e302017-07-04 22:02:49 +0900144 if (Context.USB_SERVICE.equals(name)) return mUsbManager;
Erik Klineea9cc482017-03-10 19:35:34 +0900145 return super.getSystemService(name);
146 }
147 }
148
Erik Kline8351faa2017-04-17 16:47:23 +0900149 @Before
150 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700151 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700152 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
153 .thenReturn(new String[0]);
154 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
155 .thenReturn(new String[0]);
156 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Klinec438e302017-07-04 22:02:49 +0900157 .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700158 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
159 .thenReturn(new String[0]);
160 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
161 .thenReturn(new int[0]);
Erik Klineea9cc482017-03-10 19:35:34 +0900162 when(mNMService.listInterfaces())
163 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
164 when(mNMService.getInterfaceConfig(anyString()))
165 .thenReturn(new InterfaceConfiguration());
166
167 mServiceContext = new MockContext(mContext);
Erik Kline92c4db02017-05-31 10:21:32 +0900168 mContentResolver = new MockContentResolver(mServiceContext);
169 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline8351faa2017-04-17 16:47:23 +0900170 mIntents = new Vector<>();
171 mBroadcastReceiver = new BroadcastReceiver() {
172 @Override
173 public void onReceive(Context context, Intent intent) {
174 mIntents.addElement(intent);
175 }
176 };
177 mServiceContext.registerReceiver(mBroadcastReceiver,
178 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Klinef4b6e342017-04-25 19:19:59 +0900179 when(mTetheringDependencies.getOffloadHardwareInterface(
180 any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
Erik Klineea9cc482017-03-10 19:35:34 +0900181 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Erik Kline5a7c8a02017-04-30 19:36:15 +0900182 mLooper.getLooper(), mSystemProperties,
183 mTetheringDependencies);
Lorenzo Colitti5a7dea12017-07-12 15:48:07 +0900184 verify(mNMService).registerTetheringStatsProvider(any(), anyString());
Christopher Wiley497c1472016-10-11 13:26:03 -0700185 }
186
Erik Kline8351faa2017-04-17 16:47:23 +0900187 @After
188 public void tearDown() {
189 mServiceContext.unregisterReceiver(mBroadcastReceiver);
190 }
191
Christopher Wiley497c1472016-10-11 13:26:03 -0700192 private void setupForRequiredProvisioning() {
193 // Produce some acceptable looking provision app setting if requested.
194 when(mResources.getStringArray(
195 com.android.internal.R.array.config_mobile_hotspot_provision_app))
196 .thenReturn(PROVISIONING_APP_NAME);
197 // Don't disable tethering provisioning unless requested.
198 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
199 anyBoolean())).thenReturn(false);
200 // Act like the CarrierConfigManager is present and ready unless told otherwise.
201 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
202 .thenReturn(mCarrierConfigManager);
203 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
204 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
205 }
206
207 @Test
208 public void canRequireProvisioning() {
209 setupForRequiredProvisioning();
210 assertTrue(mTethering.isTetherProvisioningRequired());
211 }
212
213 @Test
214 public void toleratesCarrierConfigManagerMissing() {
215 setupForRequiredProvisioning();
216 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
217 .thenReturn(null);
218 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
219 // We therefore still require provisioning.
220 assertTrue(mTethering.isTetherProvisioningRequired());
221 }
222
223 @Test
224 public void toleratesCarrierConfigMissing() {
225 setupForRequiredProvisioning();
226 when(mCarrierConfigManager.getConfig()).thenReturn(null);
227 // We still have a provisioning app configured, so still require provisioning.
228 assertTrue(mTethering.isTetherProvisioningRequired());
229 }
230
231 @Test
232 public void provisioningNotRequiredWhenAppNotFound() {
233 setupForRequiredProvisioning();
234 when(mResources.getStringArray(
235 com.android.internal.R.array.config_mobile_hotspot_provision_app))
236 .thenReturn(null);
237 assertTrue(!mTethering.isTetherProvisioningRequired());
238 when(mResources.getStringArray(
239 com.android.internal.R.array.config_mobile_hotspot_provision_app))
240 .thenReturn(new String[] {"malformedApp"});
241 assertTrue(!mTethering.isTetherProvisioningRequired());
242 }
Erik Klineea9cc482017-03-10 19:35:34 +0900243
244 private void sendWifiApStateChanged(int state) {
245 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
Erik Kline2efb8272017-05-31 15:53:53 +0900246 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
Erik Klineea9cc482017-03-10 19:35:34 +0900247 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
248 }
249
Erik Kline2efb8272017-05-31 15:53:53 +0900250 private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
251 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
252 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
253 intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
254 intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
255 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
256 }
257
Erik Klinec438e302017-07-04 22:02:49 +0900258 private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
259 final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
260 intent.putExtra(USB_CONNECTED, connected);
261 intent.putExtra(USB_CONFIGURED, configured);
262 intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
263 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
264 }
265
Erik Kline9e225542017-06-08 17:48:48 +0900266 private void verifyInterfaceServingModeStarted() throws Exception {
Erik Kline8351faa2017-04-17 16:47:23 +0900267 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
268 verify(mNMService, times(1))
269 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
270 verify(mNMService, times(1)).tetherInterface(mTestIfname);
271 }
272
273 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
274 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
275 final Intent bcast = mIntents.get(0);
276 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
277 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
278 assertTrue(ifnames.contains(ifname));
279 mIntents.remove(bcast);
280 }
281
Erik Klinea9cde8b2017-06-20 21:18:31 +0900282 public void failingLocalOnlyHotspotLegacyApBroadcast(
283 boolean emulateInterfaceStatusChanged) throws Exception {
Erik Klineea9cc482017-03-10 19:35:34 +0900284 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900285
286 // Emulate externally-visible WifiManager effects, causing the
287 // per-interface state machine to start up, and telling us that
288 // hotspot mode is to be started.
Erik Klinea9cde8b2017-06-20 21:18:31 +0900289 if (emulateInterfaceStatusChanged) {
290 mTethering.interfaceStatusChanged(mTestIfname, true);
291 }
Erik Kline9e225542017-06-08 17:48:48 +0900292 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Klineea9cc482017-03-10 19:35:34 +0900293 mLooper.dispatchAll();
294
Erik Klinea9cde8b2017-06-20 21:18:31 +0900295 // If, and only if, Tethering received an interface status changed
296 // then it creates a TetherInterfaceStateMachine and sends out a
297 // broadcast indicating that the interface is "available".
298 if (emulateInterfaceStatusChanged) {
299 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
300 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
301 }
Erik Kline9e225542017-06-08 17:48:48 +0900302 verifyNoMoreInteractions(mConnectivityManager);
303 verifyNoMoreInteractions(mNMService);
304 verifyNoMoreInteractions(mWifiManager);
305 }
306
307 @Test
Erik Klinec438e302017-07-04 22:02:49 +0900308 public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
309 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
310
311 // Emulate pressing the USB tethering button in Settings UI.
312 mTethering.startTethering(TETHERING_USB, null, false);
313 mLooper.dispatchAll();
314 verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
315
316 // Pretend we receive a USB connected broadcast. Here we also pretend
317 // that the RNDIS function is somehow enabled, so that we see if we
318 // might trip ourselves up.
319 sendUsbBroadcast(true, false, true);
320 mLooper.dispatchAll();
321 // This should produce no activity of any kind.
322 verifyNoMoreInteractions(mConnectivityManager);
323 verifyNoMoreInteractions(mNMService);
324
325 // Pretend we then receive USB configured broadcast.
326 sendUsbBroadcast(true, true, true);
327 mLooper.dispatchAll();
328 // Now we should see the start of tethering mechanics (in this case:
329 // tetherMatchingInterfaces() which starts by fetching all interfaces).
330 verify(mNMService, times(1)).listInterfaces();
331 }
332
333 @Test
Erik Klinea9cde8b2017-06-20 21:18:31 +0900334 public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
335 failingLocalOnlyHotspotLegacyApBroadcast(true);
336 }
337
338 @Test
339 public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
340 failingLocalOnlyHotspotLegacyApBroadcast(false);
341 }
342
343 public void workingLocalOnlyHotspotEnrichedApBroadcast(
344 boolean emulateInterfaceStatusChanged) throws Exception {
Erik Kline9e225542017-06-08 17:48:48 +0900345 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
346
347 // Emulate externally-visible WifiManager effects, causing the
348 // per-interface state machine to start up, and telling us that
349 // hotspot mode is to be started.
Erik Klinea9cde8b2017-06-20 21:18:31 +0900350 if (emulateInterfaceStatusChanged) {
351 mTethering.interfaceStatusChanged(mTestIfname, true);
352 }
Erik Kline9e225542017-06-08 17:48:48 +0900353 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
354 mLooper.dispatchAll();
355
356 verifyInterfaceServingModeStarted();
Erik Kline8351faa2017-04-17 16:47:23 +0900357 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900358 verify(mNMService, times(1)).setIpForwardingEnabled(true);
359 verify(mNMService, times(1)).startTethering(any(String[].class));
360 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900361 verify(mWifiManager).updateInterfaceIpState(
362 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
363 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900364 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900365 // UpstreamNetworkMonitor will be started, and will register two callbacks:
366 // a "listen all" and a "track default".
367 verify(mConnectivityManager, times(1)).registerNetworkCallback(
368 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
369 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
370 any(NetworkCallback.class), any(Handler.class));
371 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
372 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
373 verifyNoMoreInteractions(mConnectivityManager);
374
375 // Emulate externally-visible WifiManager effects, when hotspot mode
376 // is being torn down.
377 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
378 mTethering.interfaceRemoved(mTestIfname);
379 mLooper.dispatchAll();
380
381 verify(mNMService, times(1)).untetherInterface(mTestIfname);
382 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
383 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
384 verify(mNMService, atLeastOnce())
385 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
386 verify(mNMService, times(1)).stopTethering();
387 verify(mNMService, times(1)).setIpForwardingEnabled(false);
388 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900389 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900390 // Asking for the last error after the per-interface state machine
391 // has been reaped yields an unknown interface error.
392 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
393 mTethering.getLastTetherError(mTestIfname));
394 }
395
396 @Test
Erik Klinea9cde8b2017-06-20 21:18:31 +0900397 public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
398 workingLocalOnlyHotspotEnrichedApBroadcast(true);
399 }
400
401 @Test
402 public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
403 workingLocalOnlyHotspotEnrichedApBroadcast(false);
404 }
405
406 // TODO: Test with and without interfaceStatusChanged().
407 @Test
Erik Kline9e225542017-06-08 17:48:48 +0900408 public void failingWifiTetheringLegacyApBroadcast() throws Exception {
Erik Klineea9cc482017-03-10 19:35:34 +0900409 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineceb54c62017-04-18 14:22:25 +0900410 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900411
412 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900413 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Klineea9cc482017-03-10 19:35:34 +0900414 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900415 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Klineea9cc482017-03-10 19:35:34 +0900416 verifyNoMoreInteractions(mWifiManager);
417 verifyNoMoreInteractions(mConnectivityManager);
418 verifyNoMoreInteractions(mNMService);
419
420 // Emulate externally-visible WifiManager effects, causing the
421 // per-interface state machine to start up, and telling us that
422 // tethering mode is to be started.
423 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900424 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Klineea9cc482017-03-10 19:35:34 +0900425 mLooper.dispatchAll();
426
Erik Kline9e225542017-06-08 17:48:48 +0900427 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
428 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
429 verifyNoMoreInteractions(mConnectivityManager);
430 verifyNoMoreInteractions(mNMService);
431 verifyNoMoreInteractions(mWifiManager);
432 }
433
Erik Klinea9cde8b2017-06-20 21:18:31 +0900434 // TODO: Test with and without interfaceStatusChanged().
Erik Kline9e225542017-06-08 17:48:48 +0900435 @Test
436 public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
437 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
438 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
439
440 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900441 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Kline9e225542017-06-08 17:48:48 +0900442 mLooper.dispatchAll();
443 verify(mWifiManager, times(1)).startSoftAp(null);
444 verifyNoMoreInteractions(mWifiManager);
445 verifyNoMoreInteractions(mConnectivityManager);
446 verifyNoMoreInteractions(mNMService);
447
448 // Emulate externally-visible WifiManager effects, causing the
449 // per-interface state machine to start up, and telling us that
450 // tethering mode is to be started.
451 mTethering.interfaceStatusChanged(mTestIfname, true);
452 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
453 mLooper.dispatchAll();
454
455 verifyInterfaceServingModeStarted();
Erik Kline8351faa2017-04-17 16:47:23 +0900456 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900457 verify(mNMService, times(1)).setIpForwardingEnabled(true);
458 verify(mNMService, times(1)).startTethering(any(String[].class));
459 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900460 verify(mWifiManager).updateInterfaceIpState(
461 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
462 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900463 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900464 // UpstreamNetworkMonitor will be started, and will register two callbacks:
465 // a "listen all" and a "track default".
466 verify(mConnectivityManager, times(1)).registerNetworkCallback(
467 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
468 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
469 any(NetworkCallback.class), any(Handler.class));
470 // In tethering mode, in the default configuration, an explicit request
471 // for a mobile network is also made.
Erik Klineea9cc482017-03-10 19:35:34 +0900472 verify(mConnectivityManager, times(1)).requestNetwork(
473 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
474 any(Handler.class));
475 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
476 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
477 verifyNoMoreInteractions(mConnectivityManager);
478
479 /////
480 // We do not currently emulate any upstream being found.
481 //
482 // This is why there are no calls to verify mNMService.enableNat() or
483 // mNMService.startInterfaceForwarding().
484 /////
485
486 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900487 mTethering.stopTethering(TETHERING_WIFI);
Erik Klineea9cc482017-03-10 19:35:34 +0900488 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900489 verify(mWifiManager, times(1)).stopSoftAp();
Erik Klineea9cc482017-03-10 19:35:34 +0900490 verifyNoMoreInteractions(mWifiManager);
491 verifyNoMoreInteractions(mConnectivityManager);
492 verifyNoMoreInteractions(mNMService);
493
494 // Emulate externally-visible WifiManager effects, when tethering mode
495 // is being torn down.
496 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
497 mTethering.interfaceRemoved(mTestIfname);
498 mLooper.dispatchAll();
499
500 verify(mNMService, times(1)).untetherInterface(mTestIfname);
501 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
502 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
503 verify(mNMService, atLeastOnce())
504 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
505 verify(mNMService, times(1)).stopTethering();
506 verify(mNMService, times(1)).setIpForwardingEnabled(false);
507 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900508 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900509 // Asking for the last error after the per-interface state machine
510 // has been reaped yields an unknown interface error.
511 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
512 mTethering.getLastTetherError(mTestIfname));
513 }
514
Erik Klinea9cde8b2017-06-20 21:18:31 +0900515 // TODO: Test with and without interfaceStatusChanged().
Erik Kline1fdc2e22017-05-08 17:56:35 +0900516 @Test
517 public void failureEnablingIpForwarding() throws Exception {
518 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
519 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
520 doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
521
522 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900523 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Kline1fdc2e22017-05-08 17:56:35 +0900524 mLooper.dispatchAll();
525 verify(mWifiManager, times(1)).startSoftAp(null);
526 verifyNoMoreInteractions(mWifiManager);
527 verifyNoMoreInteractions(mConnectivityManager);
528 verifyNoMoreInteractions(mNMService);
529
530 // Emulate externally-visible WifiManager effects, causing the
531 // per-interface state machine to start up, and telling us that
532 // tethering mode is to be started.
533 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900534 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
Erik Kline1fdc2e22017-05-08 17:56:35 +0900535 mLooper.dispatchAll();
536
Erik Kline1fdc2e22017-05-08 17:56:35 +0900537 // We verify get/set called twice here: once for setup and once during
538 // teardown because all events happen over the course of the single
539 // dispatchAll() above.
540 verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
541 verify(mNMService, times(2))
542 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
543 verify(mNMService, times(1)).tetherInterface(mTestIfname);
544 verify(mWifiManager).updateInterfaceIpState(
545 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
546 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
547 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
548 // This is called, but will throw.
549 verify(mNMService, times(1)).setIpForwardingEnabled(true);
550 // This never gets called because of the exception thrown above.
551 verify(mNMService, times(0)).startTethering(any(String[].class));
552 // When the master state machine transitions to an error state it tells
553 // downstream interfaces, which causes us to tell Wi-Fi about the error
554 // so it can take down AP mode.
555 verify(mNMService, times(1)).untetherInterface(mTestIfname);
556 verify(mWifiManager).updateInterfaceIpState(
557 mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
558
559 verifyNoMoreInteractions(mWifiManager);
560 verifyNoMoreInteractions(mConnectivityManager);
561 verifyNoMoreInteractions(mNMService);
562 }
563
Alexandru-Andrei Rotarufa6d5c52017-07-18 16:49:22 +0100564 private void userRestrictionsListenerBehaviour(
565 boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
566 int expectedInteractionsWithShowNotification) throws Exception {
567 final int userId = 0;
568 final Bundle currRestrictions = new Bundle();
569 final Bundle newRestrictions = new Bundle();
570 Tethering tethering = mock(Tethering.class);
571 Tethering.TetheringUserRestrictionListener turl =
572 new Tethering.TetheringUserRestrictionListener(tethering);
573
574 currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow);
575 newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
576 when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
577
578 turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions);
579
580 verify(tethering, times(expectedInteractionsWithShowNotification))
581 .showTetheredNotification(anyInt(), eq(false));
582
583 verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll();
584 }
585
586 @Test
587 public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
588 final String[] emptyActiveIfacesList = new String[]{};
589 final boolean currDisallow = false;
590 final boolean nextDisallow = true;
591 final int expectedInteractionsWithShowNotification = 0;
592
593 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList,
594 expectedInteractionsWithShowNotification);
595 }
596
597 @Test
598 public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
599 final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
600 final boolean currDisallow = false;
601 final boolean nextDisallow = true;
602 final int expectedInteractionsWithShowNotification = 1;
603
604 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
605 expectedInteractionsWithShowNotification);
606 }
607
608 @Test
609 public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
610 final String[] nonEmptyActiveIfacesList = new String[]{};
611 final boolean currDisallow = true;
612 final boolean nextDisallow = false;
613 final int expectedInteractionsWithShowNotification = 0;
614
615 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
616 expectedInteractionsWithShowNotification);
617 }
618
619 @Test
620 public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
621 final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
622 final boolean currDisallow = true;
623 final boolean nextDisallow = false;
624 final int expectedInteractionsWithShowNotification = 0;
625
626 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
627 expectedInteractionsWithShowNotification);
628 }
629
630 @Test
631 public void testDisallowTetheringUnchanged() throws Exception {
632 final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
633 final int expectedInteractionsWithShowNotification = 0;
634 boolean currDisallow = true;
635 boolean nextDisallow = true;
636
637 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
638 expectedInteractionsWithShowNotification);
639
640 currDisallow = false;
641 nextDisallow = false;
642
643 userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
644 expectedInteractionsWithShowNotification);
645 }
646
647
Erik Kline1fdc2e22017-05-08 17:56:35 +0900648 // TODO: Test that a request for hotspot mode doesn't interfere with an
Erik Klineea9cc482017-03-10 19:35:34 +0900649 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700650}