blob: 241b828d8f4dd677045ff0bd6a6b862e7dafee8e [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;
Erik Kline92c4db02017-05-31 10:21:32 +090034import android.content.ContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070035import android.content.Context;
Erik Klineea9cc482017-03-10 19:35:34 +090036import android.content.ContextWrapper;
37import android.content.Intent;
Erik Kline8351faa2017-04-17 16:47:23 +090038import android.content.IntentFilter;
Christopher Wiley497c1472016-10-11 13:26:03 -070039import android.content.res.Resources;
Erik Klineea9cc482017-03-10 19:35:34 +090040import android.hardware.usb.UsbManager;
41import android.net.ConnectivityManager;
42import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070043import android.net.INetworkPolicyManager;
44import android.net.INetworkStatsService;
Erik Klineea9cc482017-03-10 19:35:34 +090045import android.net.InterfaceConfiguration;
46import android.net.NetworkRequest;
Erik Klinef4b6e342017-04-25 19:19:59 +090047import android.net.util.SharedLog;
Erik Klineea9cc482017-03-10 19:35:34 +090048import android.net.wifi.WifiConfiguration;
49import android.net.wifi.WifiManager;
50import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070051import android.os.INetworkManagementService;
52import android.os.PersistableBundle;
Erik Kline1fdc2e22017-05-08 17:56:35 +090053import android.os.RemoteException;
Christopher Wiley497c1472016-10-11 13:26:03 -070054import android.os.test.TestLooper;
Erik Klineea9cc482017-03-10 19:35:34 +090055import android.os.UserHandle;
Erik Kline92c4db02017-05-31 10:21:32 +090056import android.provider.Settings;
Christopher Wiley497c1472016-10-11 13:26:03 -070057import android.support.test.filters.SmallTest;
58import android.support.test.runner.AndroidJUnit4;
59import android.telephony.CarrierConfigManager;
Erik Kline92c4db02017-05-31 10:21:32 +090060import android.test.mock.MockContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070061
Erik Klineea9cc482017-03-10 19:35:34 +090062import com.android.internal.util.test.BroadcastInterceptingContext;
Erik Kline92c4db02017-05-31 10:21:32 +090063import com.android.internal.util.test.FakeSettingsProvider;
Erik Kline5a7c8a02017-04-30 19:36:15 +090064import com.android.server.connectivity.tethering.OffloadHardwareInterface;
65import com.android.server.connectivity.tethering.TetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090066
Erik Kline8351faa2017-04-17 16:47:23 +090067import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070068import org.junit.Before;
69import org.junit.Test;
70import org.junit.runner.RunWith;
71import org.mockito.Mock;
72import org.mockito.MockitoAnnotations;
73
Erik Kline8351faa2017-04-17 16:47:23 +090074import java.util.ArrayList;
75import java.util.Vector;
76
Christopher Wiley497c1472016-10-11 13:26:03 -070077@RunWith(AndroidJUnit4.class)
78@SmallTest
79public class TetheringTest {
80 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
81
82 @Mock private Context mContext;
Erik Klineea9cc482017-03-10 19:35:34 +090083 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070084 @Mock private INetworkManagementService mNMService;
85 @Mock private INetworkStatsService mStatsService;
86 @Mock private INetworkPolicyManager mPolicyManager;
87 @Mock private MockableSystemProperties mSystemProperties;
Erik Kline5a7c8a02017-04-30 19:36:15 +090088 @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
Christopher Wiley497c1472016-10-11 13:26:03 -070089 @Mock private Resources mResources;
Erik Kline5a7c8a02017-04-30 19:36:15 +090090 @Mock private TetheringDependencies mTetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090091 @Mock private UsbManager mUsbManager;
92 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070093 @Mock private CarrierConfigManager mCarrierConfigManager;
94
95 // Like so many Android system APIs, these cannot be mocked because it is marked final.
96 // We have to use the real versions.
97 private final PersistableBundle mCarrierConfig = new PersistableBundle();
98 private final TestLooper mLooper = new TestLooper();
Erik Klineea9cc482017-03-10 19:35:34 +090099 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -0700100
Erik Kline8351faa2017-04-17 16:47:23 +0900101 private Vector<Intent> mIntents;
Erik Klineea9cc482017-03-10 19:35:34 +0900102 private BroadcastInterceptingContext mServiceContext;
Erik Kline92c4db02017-05-31 10:21:32 +0900103 private MockContentResolver mContentResolver;
Erik Kline8351faa2017-04-17 16:47:23 +0900104 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -0700105 private Tethering mTethering;
106
Erik Klineea9cc482017-03-10 19:35:34 +0900107 private class MockContext extends BroadcastInterceptingContext {
108 MockContext(Context base) {
109 super(base);
110 }
111
112 @Override
Erik Kline92c4db02017-05-31 10:21:32 +0900113 public ContentResolver getContentResolver() { return mContentResolver; }
114
115 @Override
116 public String getPackageName() { return "TetheringTest"; }
117
118 @Override
Erik Klineea9cc482017-03-10 19:35:34 +0900119 public Resources getResources() { return mResources; }
120
121 @Override
122 public Object getSystemService(String name) {
123 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
124 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
125 return super.getSystemService(name);
126 }
127 }
128
Erik Kline8351faa2017-04-17 16:47:23 +0900129 @Before
130 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700131 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700132 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
133 .thenReturn(new String[0]);
134 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
135 .thenReturn(new String[0]);
136 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Klineea9cc482017-03-10 19:35:34 +0900137 .thenReturn(new String[]{ "test_wlan\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700138 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
139 .thenReturn(new String[0]);
140 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
141 .thenReturn(new int[0]);
Erik Klineea9cc482017-03-10 19:35:34 +0900142 when(mNMService.listInterfaces())
143 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
144 when(mNMService.getInterfaceConfig(anyString()))
145 .thenReturn(new InterfaceConfiguration());
146
147 mServiceContext = new MockContext(mContext);
Erik Kline92c4db02017-05-31 10:21:32 +0900148 mContentResolver = new MockContentResolver(mServiceContext);
149 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline8351faa2017-04-17 16:47:23 +0900150 mIntents = new Vector<>();
151 mBroadcastReceiver = new BroadcastReceiver() {
152 @Override
153 public void onReceive(Context context, Intent intent) {
154 mIntents.addElement(intent);
155 }
156 };
157 mServiceContext.registerReceiver(mBroadcastReceiver,
158 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Klinef4b6e342017-04-25 19:19:59 +0900159 when(mTetheringDependencies.getOffloadHardwareInterface(
160 any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
Erik Klineea9cc482017-03-10 19:35:34 +0900161 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Erik Kline5a7c8a02017-04-30 19:36:15 +0900162 mLooper.getLooper(), mSystemProperties,
163 mTetheringDependencies);
Christopher Wiley497c1472016-10-11 13:26:03 -0700164 }
165
Erik Kline8351faa2017-04-17 16:47:23 +0900166 @After
167 public void tearDown() {
168 mServiceContext.unregisterReceiver(mBroadcastReceiver);
169 }
170
Christopher Wiley497c1472016-10-11 13:26:03 -0700171 private void setupForRequiredProvisioning() {
172 // Produce some acceptable looking provision app setting if requested.
173 when(mResources.getStringArray(
174 com.android.internal.R.array.config_mobile_hotspot_provision_app))
175 .thenReturn(PROVISIONING_APP_NAME);
176 // Don't disable tethering provisioning unless requested.
177 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
178 anyBoolean())).thenReturn(false);
179 // Act like the CarrierConfigManager is present and ready unless told otherwise.
180 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
181 .thenReturn(mCarrierConfigManager);
182 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
183 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
184 }
185
186 @Test
187 public void canRequireProvisioning() {
188 setupForRequiredProvisioning();
189 assertTrue(mTethering.isTetherProvisioningRequired());
190 }
191
192 @Test
193 public void toleratesCarrierConfigManagerMissing() {
194 setupForRequiredProvisioning();
195 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
196 .thenReturn(null);
197 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
198 // We therefore still require provisioning.
199 assertTrue(mTethering.isTetherProvisioningRequired());
200 }
201
202 @Test
203 public void toleratesCarrierConfigMissing() {
204 setupForRequiredProvisioning();
205 when(mCarrierConfigManager.getConfig()).thenReturn(null);
206 // We still have a provisioning app configured, so still require provisioning.
207 assertTrue(mTethering.isTetherProvisioningRequired());
208 }
209
210 @Test
211 public void provisioningNotRequiredWhenAppNotFound() {
212 setupForRequiredProvisioning();
213 when(mResources.getStringArray(
214 com.android.internal.R.array.config_mobile_hotspot_provision_app))
215 .thenReturn(null);
216 assertTrue(!mTethering.isTetherProvisioningRequired());
217 when(mResources.getStringArray(
218 com.android.internal.R.array.config_mobile_hotspot_provision_app))
219 .thenReturn(new String[] {"malformedApp"});
220 assertTrue(!mTethering.isTetherProvisioningRequired());
221 }
Erik Klineea9cc482017-03-10 19:35:34 +0900222
223 private void sendWifiApStateChanged(int state) {
224 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
225 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, state);
226 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
227 }
228
Erik Kline8351faa2017-04-17 16:47:23 +0900229 private void verifyInterfaceServingModeStarted() throws Exception {
230 verify(mNMService, times(1)).listInterfaces();
231 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
232 verify(mNMService, times(1))
233 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
234 verify(mNMService, times(1)).tetherInterface(mTestIfname);
235 }
236
237 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
238 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
239 final Intent bcast = mIntents.get(0);
240 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
241 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
242 assertTrue(ifnames.contains(ifname));
243 mIntents.remove(bcast);
244 }
245
Erik Klineea9cc482017-03-10 19:35:34 +0900246 @Test
247 public void workingLocalOnlyHotspot() throws Exception {
248 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900249
250 // Emulate externally-visible WifiManager effects, causing the
251 // per-interface state machine to start up, and telling us that
252 // hotspot mode is to be started.
253 mTethering.interfaceStatusChanged(mTestIfname, true);
254 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
255 mLooper.dispatchAll();
256
Erik Kline8351faa2017-04-17 16:47:23 +0900257 verifyInterfaceServingModeStarted();
258 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900259 verify(mNMService, times(1)).setIpForwardingEnabled(true);
260 verify(mNMService, times(1)).startTethering(any(String[].class));
261 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900262 verify(mWifiManager).updateInterfaceIpState(
263 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
264 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900265 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900266 // UpstreamNetworkMonitor will be started, and will register two callbacks:
267 // a "listen all" and a "track default".
268 verify(mConnectivityManager, times(1)).registerNetworkCallback(
269 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
270 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
271 any(NetworkCallback.class), any(Handler.class));
272 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
273 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
274 verifyNoMoreInteractions(mConnectivityManager);
275
276 // Emulate externally-visible WifiManager effects, when hotspot mode
277 // is being torn down.
278 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
279 mTethering.interfaceRemoved(mTestIfname);
280 mLooper.dispatchAll();
281
282 verify(mNMService, times(1)).untetherInterface(mTestIfname);
283 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
284 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
285 verify(mNMService, atLeastOnce())
286 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
287 verify(mNMService, times(1)).stopTethering();
288 verify(mNMService, times(1)).setIpForwardingEnabled(false);
289 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900290 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900291 // Asking for the last error after the per-interface state machine
292 // has been reaped yields an unknown interface error.
293 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
294 mTethering.getLastTetherError(mTestIfname));
295 }
296
297 @Test
298 public void workingWifiTethering() throws Exception {
299 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineceb54c62017-04-18 14:22:25 +0900300 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900301
302 // Emulate pressing the WiFi tethering button.
303 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
304 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900305 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Klineea9cc482017-03-10 19:35:34 +0900306 verifyNoMoreInteractions(mWifiManager);
307 verifyNoMoreInteractions(mConnectivityManager);
308 verifyNoMoreInteractions(mNMService);
309
310 // Emulate externally-visible WifiManager effects, causing the
311 // per-interface state machine to start up, and telling us that
312 // tethering mode is to be started.
313 mTethering.interfaceStatusChanged(mTestIfname, true);
314 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
315 mLooper.dispatchAll();
316
Erik Kline8351faa2017-04-17 16:47:23 +0900317 verifyInterfaceServingModeStarted();
318 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900319 verify(mNMService, times(1)).setIpForwardingEnabled(true);
320 verify(mNMService, times(1)).startTethering(any(String[].class));
321 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900322 verify(mWifiManager).updateInterfaceIpState(
323 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
324 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900325 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900326 // UpstreamNetworkMonitor will be started, and will register two callbacks:
327 // a "listen all" and a "track default".
328 verify(mConnectivityManager, times(1)).registerNetworkCallback(
329 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
330 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
331 any(NetworkCallback.class), any(Handler.class));
332 // In tethering mode, in the default configuration, an explicit request
333 // for a mobile network is also made.
334 verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
335 verify(mConnectivityManager, times(1)).requestNetwork(
336 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
337 any(Handler.class));
338 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
339 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
340 verifyNoMoreInteractions(mConnectivityManager);
341
342 /////
343 // We do not currently emulate any upstream being found.
344 //
345 // This is why there are no calls to verify mNMService.enableNat() or
346 // mNMService.startInterfaceForwarding().
347 /////
348
349 // Emulate pressing the WiFi tethering button.
350 mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
351 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900352 verify(mWifiManager, times(1)).stopSoftAp();
Erik Klineea9cc482017-03-10 19:35:34 +0900353 verifyNoMoreInteractions(mWifiManager);
354 verifyNoMoreInteractions(mConnectivityManager);
355 verifyNoMoreInteractions(mNMService);
356
357 // Emulate externally-visible WifiManager effects, when tethering mode
358 // is being torn down.
359 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
360 mTethering.interfaceRemoved(mTestIfname);
361 mLooper.dispatchAll();
362
363 verify(mNMService, times(1)).untetherInterface(mTestIfname);
364 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
365 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
366 verify(mNMService, atLeastOnce())
367 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
368 verify(mNMService, times(1)).stopTethering();
369 verify(mNMService, times(1)).setIpForwardingEnabled(false);
370 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900371 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900372 // Asking for the last error after the per-interface state machine
373 // has been reaped yields an unknown interface error.
374 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
375 mTethering.getLastTetherError(mTestIfname));
376 }
377
Erik Kline1fdc2e22017-05-08 17:56:35 +0900378 @Test
379 public void failureEnablingIpForwarding() throws Exception {
380 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
381 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
382 doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
383
384 // Emulate pressing the WiFi tethering button.
385 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
386 mLooper.dispatchAll();
387 verify(mWifiManager, times(1)).startSoftAp(null);
388 verifyNoMoreInteractions(mWifiManager);
389 verifyNoMoreInteractions(mConnectivityManager);
390 verifyNoMoreInteractions(mNMService);
391
392 // Emulate externally-visible WifiManager effects, causing the
393 // per-interface state machine to start up, and telling us that
394 // tethering mode is to be started.
395 mTethering.interfaceStatusChanged(mTestIfname, true);
396 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
397 mLooper.dispatchAll();
398
399 // Activity caused by test_wlan0 becoming available.
400 verify(mNMService, times(1)).listInterfaces();
401 // We verify get/set called twice here: once for setup and once during
402 // teardown because all events happen over the course of the single
403 // dispatchAll() above.
404 verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
405 verify(mNMService, times(2))
406 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
407 verify(mNMService, times(1)).tetherInterface(mTestIfname);
408 verify(mWifiManager).updateInterfaceIpState(
409 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
410 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
411 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
412 // This is called, but will throw.
413 verify(mNMService, times(1)).setIpForwardingEnabled(true);
414 // This never gets called because of the exception thrown above.
415 verify(mNMService, times(0)).startTethering(any(String[].class));
416 // When the master state machine transitions to an error state it tells
417 // downstream interfaces, which causes us to tell Wi-Fi about the error
418 // so it can take down AP mode.
419 verify(mNMService, times(1)).untetherInterface(mTestIfname);
420 verify(mWifiManager).updateInterfaceIpState(
421 mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
422
423 verifyNoMoreInteractions(mWifiManager);
424 verifyNoMoreInteractions(mConnectivityManager);
425 verifyNoMoreInteractions(mNMService);
426 }
427
428 // TODO: Test that a request for hotspot mode doesn't interfere with an
Erik Klineea9cc482017-03-10 19:35:34 +0900429 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700430}