blob: d5a0b864583a8e9ba9cdd65302a8517b2bbd2555 [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 Klineea9cc482017-03-10 19:35:34 +090019import static org.junit.Assert.assertEquals;
Christopher Wiley497c1472016-10-11 13:26:03 -070020import static org.junit.Assert.assertTrue;
21import static org.mockito.Matchers.anyBoolean;
Erik Klineea9cc482017-03-10 19:35:34 +090022import static org.mockito.Matchers.anyInt;
23import static org.mockito.Matchers.anyString;
Christopher Wiley497c1472016-10-11 13:26:03 -070024import static org.mockito.Matchers.eq;
Erik Kline1fdc2e22017-05-08 17:56:35 +090025import static org.mockito.Mockito.any;
Erik Klineea9cc482017-03-10 19:35:34 +090026import static org.mockito.Mockito.atLeastOnce;
Erik Kline1fdc2e22017-05-08 17:56:35 +090027import static org.mockito.Mockito.doThrow;
Erik Klineea9cc482017-03-10 19:35:34 +090028import static org.mockito.Mockito.times;
29import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.verifyNoMoreInteractions;
Christopher Wiley497c1472016-10-11 13:26:03 -070031import static org.mockito.Mockito.when;
32
Erik Kline8351faa2017-04-17 16:47:23 +090033import android.content.BroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -070034import android.content.Context;
Erik Klineea9cc482017-03-10 19:35:34 +090035import android.content.ContextWrapper;
36import android.content.Intent;
Erik Kline8351faa2017-04-17 16:47:23 +090037import android.content.IntentFilter;
Christopher Wiley497c1472016-10-11 13:26:03 -070038import android.content.res.Resources;
Erik Klineea9cc482017-03-10 19:35:34 +090039import android.hardware.usb.UsbManager;
40import android.net.ConnectivityManager;
41import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070042import android.net.INetworkPolicyManager;
43import android.net.INetworkStatsService;
Erik Klineea9cc482017-03-10 19:35:34 +090044import android.net.InterfaceConfiguration;
45import android.net.NetworkRequest;
Erik Klinef4b6e342017-04-25 19:19:59 +090046import android.net.util.SharedLog;
Erik Klineea9cc482017-03-10 19:35:34 +090047import android.net.wifi.WifiConfiguration;
48import android.net.wifi.WifiManager;
49import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070050import android.os.INetworkManagementService;
51import android.os.PersistableBundle;
Erik Kline1fdc2e22017-05-08 17:56:35 +090052import android.os.RemoteException;
Christopher Wiley497c1472016-10-11 13:26:03 -070053import android.os.test.TestLooper;
Erik Klineea9cc482017-03-10 19:35:34 +090054import android.os.UserHandle;
Christopher Wiley497c1472016-10-11 13:26:03 -070055import android.support.test.filters.SmallTest;
56import android.support.test.runner.AndroidJUnit4;
57import android.telephony.CarrierConfigManager;
58
Erik Klineea9cc482017-03-10 19:35:34 +090059import com.android.internal.util.test.BroadcastInterceptingContext;
Erik Kline5a7c8a02017-04-30 19:36:15 +090060import com.android.server.connectivity.tethering.OffloadHardwareInterface;
61import com.android.server.connectivity.tethering.TetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090062
Erik Kline8351faa2017-04-17 16:47:23 +090063import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070064import org.junit.Before;
65import org.junit.Test;
66import org.junit.runner.RunWith;
67import org.mockito.Mock;
68import org.mockito.MockitoAnnotations;
69
Erik Kline8351faa2017-04-17 16:47:23 +090070import java.util.ArrayList;
71import java.util.Vector;
72
Christopher Wiley497c1472016-10-11 13:26:03 -070073@RunWith(AndroidJUnit4.class)
74@SmallTest
75public class TetheringTest {
76 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
77
78 @Mock private Context mContext;
Erik Klineea9cc482017-03-10 19:35:34 +090079 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070080 @Mock private INetworkManagementService mNMService;
81 @Mock private INetworkStatsService mStatsService;
82 @Mock private INetworkPolicyManager mPolicyManager;
83 @Mock private MockableSystemProperties mSystemProperties;
Erik Kline5a7c8a02017-04-30 19:36:15 +090084 @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
Christopher Wiley497c1472016-10-11 13:26:03 -070085 @Mock private Resources mResources;
Erik Kline5a7c8a02017-04-30 19:36:15 +090086 @Mock private TetheringDependencies mTetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090087 @Mock private UsbManager mUsbManager;
88 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070089 @Mock private CarrierConfigManager mCarrierConfigManager;
90
91 // Like so many Android system APIs, these cannot be mocked because it is marked final.
92 // We have to use the real versions.
93 private final PersistableBundle mCarrierConfig = new PersistableBundle();
94 private final TestLooper mLooper = new TestLooper();
Erik Klineea9cc482017-03-10 19:35:34 +090095 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -070096
Erik Kline8351faa2017-04-17 16:47:23 +090097 private Vector<Intent> mIntents;
Erik Klineea9cc482017-03-10 19:35:34 +090098 private BroadcastInterceptingContext mServiceContext;
Erik Kline8351faa2017-04-17 16:47:23 +090099 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -0700100 private Tethering mTethering;
101
Erik Klineea9cc482017-03-10 19:35:34 +0900102 private class MockContext extends BroadcastInterceptingContext {
103 MockContext(Context base) {
104 super(base);
105 }
106
107 @Override
108 public Resources getResources() { return mResources; }
109
110 @Override
111 public Object getSystemService(String name) {
112 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
113 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
114 return super.getSystemService(name);
115 }
116 }
117
Erik Kline8351faa2017-04-17 16:47:23 +0900118 @Before
119 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700120 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700121 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
122 .thenReturn(new String[0]);
123 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
124 .thenReturn(new String[0]);
125 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Klineea9cc482017-03-10 19:35:34 +0900126 .thenReturn(new String[]{ "test_wlan\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700127 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
128 .thenReturn(new String[0]);
129 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
130 .thenReturn(new int[0]);
Erik Klineea9cc482017-03-10 19:35:34 +0900131 when(mNMService.listInterfaces())
132 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
133 when(mNMService.getInterfaceConfig(anyString()))
134 .thenReturn(new InterfaceConfiguration());
135
136 mServiceContext = new MockContext(mContext);
Erik Kline8351faa2017-04-17 16:47:23 +0900137 mIntents = new Vector<>();
138 mBroadcastReceiver = new BroadcastReceiver() {
139 @Override
140 public void onReceive(Context context, Intent intent) {
141 mIntents.addElement(intent);
142 }
143 };
144 mServiceContext.registerReceiver(mBroadcastReceiver,
145 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Klinef4b6e342017-04-25 19:19:59 +0900146 when(mTetheringDependencies.getOffloadHardwareInterface(
147 any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
Erik Klineea9cc482017-03-10 19:35:34 +0900148 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Erik Kline5a7c8a02017-04-30 19:36:15 +0900149 mLooper.getLooper(), mSystemProperties,
150 mTetheringDependencies);
Christopher Wiley497c1472016-10-11 13:26:03 -0700151 }
152
Erik Kline8351faa2017-04-17 16:47:23 +0900153 @After
154 public void tearDown() {
155 mServiceContext.unregisterReceiver(mBroadcastReceiver);
156 }
157
Christopher Wiley497c1472016-10-11 13:26:03 -0700158 private void setupForRequiredProvisioning() {
159 // Produce some acceptable looking provision app setting if requested.
160 when(mResources.getStringArray(
161 com.android.internal.R.array.config_mobile_hotspot_provision_app))
162 .thenReturn(PROVISIONING_APP_NAME);
163 // Don't disable tethering provisioning unless requested.
164 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
165 anyBoolean())).thenReturn(false);
166 // Act like the CarrierConfigManager is present and ready unless told otherwise.
167 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
168 .thenReturn(mCarrierConfigManager);
169 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
170 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
171 }
172
173 @Test
174 public void canRequireProvisioning() {
175 setupForRequiredProvisioning();
176 assertTrue(mTethering.isTetherProvisioningRequired());
177 }
178
179 @Test
180 public void toleratesCarrierConfigManagerMissing() {
181 setupForRequiredProvisioning();
182 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
183 .thenReturn(null);
184 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
185 // We therefore still require provisioning.
186 assertTrue(mTethering.isTetherProvisioningRequired());
187 }
188
189 @Test
190 public void toleratesCarrierConfigMissing() {
191 setupForRequiredProvisioning();
192 when(mCarrierConfigManager.getConfig()).thenReturn(null);
193 // We still have a provisioning app configured, so still require provisioning.
194 assertTrue(mTethering.isTetherProvisioningRequired());
195 }
196
197 @Test
198 public void provisioningNotRequiredWhenAppNotFound() {
199 setupForRequiredProvisioning();
200 when(mResources.getStringArray(
201 com.android.internal.R.array.config_mobile_hotspot_provision_app))
202 .thenReturn(null);
203 assertTrue(!mTethering.isTetherProvisioningRequired());
204 when(mResources.getStringArray(
205 com.android.internal.R.array.config_mobile_hotspot_provision_app))
206 .thenReturn(new String[] {"malformedApp"});
207 assertTrue(!mTethering.isTetherProvisioningRequired());
208 }
Erik Klineea9cc482017-03-10 19:35:34 +0900209
210 private void sendWifiApStateChanged(int state) {
211 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
212 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, state);
213 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
214 }
215
Erik Kline8351faa2017-04-17 16:47:23 +0900216 private void verifyInterfaceServingModeStarted() throws Exception {
217 verify(mNMService, times(1)).listInterfaces();
218 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
219 verify(mNMService, times(1))
220 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
221 verify(mNMService, times(1)).tetherInterface(mTestIfname);
222 }
223
224 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
225 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
226 final Intent bcast = mIntents.get(0);
227 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
228 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
229 assertTrue(ifnames.contains(ifname));
230 mIntents.remove(bcast);
231 }
232
Erik Klineea9cc482017-03-10 19:35:34 +0900233 @Test
234 public void workingLocalOnlyHotspot() throws Exception {
235 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900236
237 // Emulate externally-visible WifiManager effects, causing the
238 // per-interface state machine to start up, and telling us that
239 // hotspot mode is to be started.
240 mTethering.interfaceStatusChanged(mTestIfname, true);
241 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
242 mLooper.dispatchAll();
243
Erik Kline8351faa2017-04-17 16:47:23 +0900244 verifyInterfaceServingModeStarted();
245 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900246 verify(mNMService, times(1)).setIpForwardingEnabled(true);
247 verify(mNMService, times(1)).startTethering(any(String[].class));
248 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900249 verify(mWifiManager).updateInterfaceIpState(
250 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
251 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900252 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900253 // UpstreamNetworkMonitor will be started, and will register two callbacks:
254 // a "listen all" and a "track default".
255 verify(mConnectivityManager, times(1)).registerNetworkCallback(
256 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
257 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
258 any(NetworkCallback.class), any(Handler.class));
259 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
260 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
261 verifyNoMoreInteractions(mConnectivityManager);
262
263 // Emulate externally-visible WifiManager effects, when hotspot mode
264 // is being torn down.
265 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
266 mTethering.interfaceRemoved(mTestIfname);
267 mLooper.dispatchAll();
268
269 verify(mNMService, times(1)).untetherInterface(mTestIfname);
270 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
271 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
272 verify(mNMService, atLeastOnce())
273 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
274 verify(mNMService, times(1)).stopTethering();
275 verify(mNMService, times(1)).setIpForwardingEnabled(false);
276 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900277 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900278 // Asking for the last error after the per-interface state machine
279 // has been reaped yields an unknown interface error.
280 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
281 mTethering.getLastTetherError(mTestIfname));
282 }
283
284 @Test
285 public void workingWifiTethering() throws Exception {
286 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineceb54c62017-04-18 14:22:25 +0900287 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900288
289 // Emulate pressing the WiFi tethering button.
290 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
291 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900292 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Klineea9cc482017-03-10 19:35:34 +0900293 verifyNoMoreInteractions(mWifiManager);
294 verifyNoMoreInteractions(mConnectivityManager);
295 verifyNoMoreInteractions(mNMService);
296
297 // Emulate externally-visible WifiManager effects, causing the
298 // per-interface state machine to start up, and telling us that
299 // tethering mode is to be started.
300 mTethering.interfaceStatusChanged(mTestIfname, true);
301 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
302 mLooper.dispatchAll();
303
Erik Kline8351faa2017-04-17 16:47:23 +0900304 verifyInterfaceServingModeStarted();
305 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900306 verify(mNMService, times(1)).setIpForwardingEnabled(true);
307 verify(mNMService, times(1)).startTethering(any(String[].class));
308 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900309 verify(mWifiManager).updateInterfaceIpState(
310 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
311 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900312 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900313 // UpstreamNetworkMonitor will be started, and will register two callbacks:
314 // a "listen all" and a "track default".
315 verify(mConnectivityManager, times(1)).registerNetworkCallback(
316 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
317 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
318 any(NetworkCallback.class), any(Handler.class));
319 // In tethering mode, in the default configuration, an explicit request
320 // for a mobile network is also made.
321 verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
322 verify(mConnectivityManager, times(1)).requestNetwork(
323 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
324 any(Handler.class));
325 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
326 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
327 verifyNoMoreInteractions(mConnectivityManager);
328
329 /////
330 // We do not currently emulate any upstream being found.
331 //
332 // This is why there are no calls to verify mNMService.enableNat() or
333 // mNMService.startInterfaceForwarding().
334 /////
335
336 // Emulate pressing the WiFi tethering button.
337 mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
338 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900339 verify(mWifiManager, times(1)).stopSoftAp();
Erik Klineea9cc482017-03-10 19:35:34 +0900340 verifyNoMoreInteractions(mWifiManager);
341 verifyNoMoreInteractions(mConnectivityManager);
342 verifyNoMoreInteractions(mNMService);
343
344 // Emulate externally-visible WifiManager effects, when tethering mode
345 // is being torn down.
346 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
347 mTethering.interfaceRemoved(mTestIfname);
348 mLooper.dispatchAll();
349
350 verify(mNMService, times(1)).untetherInterface(mTestIfname);
351 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
352 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
353 verify(mNMService, atLeastOnce())
354 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
355 verify(mNMService, times(1)).stopTethering();
356 verify(mNMService, times(1)).setIpForwardingEnabled(false);
357 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900358 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900359 // Asking for the last error after the per-interface state machine
360 // has been reaped yields an unknown interface error.
361 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
362 mTethering.getLastTetherError(mTestIfname));
363 }
364
Erik Kline1fdc2e22017-05-08 17:56:35 +0900365 @Test
366 public void failureEnablingIpForwarding() throws Exception {
367 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
368 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
369 doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
370
371 // Emulate pressing the WiFi tethering button.
372 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
373 mLooper.dispatchAll();
374 verify(mWifiManager, times(1)).startSoftAp(null);
375 verifyNoMoreInteractions(mWifiManager);
376 verifyNoMoreInteractions(mConnectivityManager);
377 verifyNoMoreInteractions(mNMService);
378
379 // Emulate externally-visible WifiManager effects, causing the
380 // per-interface state machine to start up, and telling us that
381 // tethering mode is to be started.
382 mTethering.interfaceStatusChanged(mTestIfname, true);
383 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
384 mLooper.dispatchAll();
385
386 // Activity caused by test_wlan0 becoming available.
387 verify(mNMService, times(1)).listInterfaces();
388 // We verify get/set called twice here: once for setup and once during
389 // teardown because all events happen over the course of the single
390 // dispatchAll() above.
391 verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
392 verify(mNMService, times(2))
393 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
394 verify(mNMService, times(1)).tetherInterface(mTestIfname);
395 verify(mWifiManager).updateInterfaceIpState(
396 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
397 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
398 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
399 // This is called, but will throw.
400 verify(mNMService, times(1)).setIpForwardingEnabled(true);
401 // This never gets called because of the exception thrown above.
402 verify(mNMService, times(0)).startTethering(any(String[].class));
403 // When the master state machine transitions to an error state it tells
404 // downstream interfaces, which causes us to tell Wi-Fi about the error
405 // so it can take down AP mode.
406 verify(mNMService, times(1)).untetherInterface(mTestIfname);
407 verify(mWifiManager).updateInterfaceIpState(
408 mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
409
410 verifyNoMoreInteractions(mWifiManager);
411 verifyNoMoreInteractions(mConnectivityManager);
412 verifyNoMoreInteractions(mNMService);
413 }
414
415 // TODO: Test that a request for hotspot mode doesn't interfere with an
Erik Klineea9cc482017-03-10 19:35:34 +0900416 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700417}