blob: 281223e1fe587b3598766571f8c91fe06b5ea92f [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 Kline1454ee72017-05-31 15:53:53 +090019import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
20import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
21import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
22import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
23import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
24import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
Erik Kline5f2b7992017-03-10 19:35:34 +090025import static org.junit.Assert.assertEquals;
Christopher Wiley497c1472016-10-11 13:26:03 -070026import static org.junit.Assert.assertTrue;
27import static org.mockito.Matchers.anyBoolean;
Erik Kline5f2b7992017-03-10 19:35:34 +090028import static org.mockito.Matchers.anyInt;
29import static org.mockito.Matchers.anyString;
Christopher Wiley497c1472016-10-11 13:26:03 -070030import static org.mockito.Matchers.eq;
Erik Kline38356e92017-05-08 17:56:35 +090031import static org.mockito.Mockito.any;
Erik Kline5f2b7992017-03-10 19:35:34 +090032import static org.mockito.Mockito.atLeastOnce;
Erik Kline38356e92017-05-08 17:56:35 +090033import static org.mockito.Mockito.doThrow;
Erik Kline5f2b7992017-03-10 19:35:34 +090034import static org.mockito.Mockito.times;
35import static org.mockito.Mockito.verify;
36import static org.mockito.Mockito.verifyNoMoreInteractions;
Christopher Wiley497c1472016-10-11 13:26:03 -070037import static org.mockito.Mockito.when;
38
Erik Kline668b7222017-04-17 16:47:23 +090039import android.content.BroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -070040import android.content.Context;
Erik Kline5f2b7992017-03-10 19:35:34 +090041import android.content.ContextWrapper;
42import android.content.Intent;
Erik Kline668b7222017-04-17 16:47:23 +090043import android.content.IntentFilter;
Christopher Wiley497c1472016-10-11 13:26:03 -070044import android.content.res.Resources;
Erik Kline5f2b7992017-03-10 19:35:34 +090045import android.hardware.usb.UsbManager;
46import android.net.ConnectivityManager;
47import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070048import android.net.INetworkPolicyManager;
49import android.net.INetworkStatsService;
Erik Kline5f2b7992017-03-10 19:35:34 +090050import android.net.InterfaceConfiguration;
51import android.net.NetworkRequest;
52import android.net.wifi.WifiConfiguration;
53import android.net.wifi.WifiManager;
54import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070055import android.os.INetworkManagementService;
56import android.os.PersistableBundle;
Erik Kline38356e92017-05-08 17:56:35 +090057import android.os.RemoteException;
Christopher Wiley497c1472016-10-11 13:26:03 -070058import android.os.test.TestLooper;
Erik Kline5f2b7992017-03-10 19:35:34 +090059import android.os.UserHandle;
Christopher Wiley497c1472016-10-11 13:26:03 -070060import android.support.test.filters.SmallTest;
61import android.support.test.runner.AndroidJUnit4;
62import android.telephony.CarrierConfigManager;
63
Erik Kline5f2b7992017-03-10 19:35:34 +090064import com.android.internal.util.test.BroadcastInterceptingContext;
65
Erik Kline668b7222017-04-17 16:47:23 +090066import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070067import org.junit.Before;
68import org.junit.Test;
69import org.junit.runner.RunWith;
70import org.mockito.Mock;
71import org.mockito.MockitoAnnotations;
72
Erik Kline668b7222017-04-17 16:47:23 +090073import java.util.ArrayList;
74import java.util.Vector;
75
Christopher Wiley497c1472016-10-11 13:26:03 -070076@RunWith(AndroidJUnit4.class)
77@SmallTest
78public class TetheringTest {
79 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
80
81 @Mock private Context mContext;
Erik Kline5f2b7992017-03-10 19:35:34 +090082 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070083 @Mock private INetworkManagementService mNMService;
84 @Mock private INetworkStatsService mStatsService;
85 @Mock private INetworkPolicyManager mPolicyManager;
86 @Mock private MockableSystemProperties mSystemProperties;
87 @Mock private Resources mResources;
Erik Kline5f2b7992017-03-10 19:35:34 +090088 @Mock private UsbManager mUsbManager;
89 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070090 @Mock private CarrierConfigManager mCarrierConfigManager;
91
92 // Like so many Android system APIs, these cannot be mocked because it is marked final.
93 // We have to use the real versions.
94 private final PersistableBundle mCarrierConfig = new PersistableBundle();
95 private final TestLooper mLooper = new TestLooper();
Erik Kline5f2b7992017-03-10 19:35:34 +090096 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -070097
Erik Kline668b7222017-04-17 16:47:23 +090098 private Vector<Intent> mIntents;
Erik Kline5f2b7992017-03-10 19:35:34 +090099 private BroadcastInterceptingContext mServiceContext;
Erik Kline668b7222017-04-17 16:47:23 +0900100 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -0700101 private Tethering mTethering;
102
Erik Kline5f2b7992017-03-10 19:35:34 +0900103 private class MockContext extends BroadcastInterceptingContext {
104 MockContext(Context base) {
105 super(base);
106 }
107
108 @Override
109 public Resources getResources() { return mResources; }
110
111 @Override
112 public Object getSystemService(String name) {
113 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
114 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
115 return super.getSystemService(name);
116 }
117 }
118
Erik Kline668b7222017-04-17 16:47:23 +0900119 @Before
120 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700121 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700122 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
123 .thenReturn(new String[0]);
124 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
125 .thenReturn(new String[0]);
126 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Kline5f2b7992017-03-10 19:35:34 +0900127 .thenReturn(new String[]{ "test_wlan\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700128 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
129 .thenReturn(new String[0]);
130 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
131 .thenReturn(new int[0]);
Erik Kline5f2b7992017-03-10 19:35:34 +0900132 when(mNMService.listInterfaces())
133 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
134 when(mNMService.getInterfaceConfig(anyString()))
135 .thenReturn(new InterfaceConfiguration());
136
137 mServiceContext = new MockContext(mContext);
Erik Kline668b7222017-04-17 16:47:23 +0900138 mIntents = new Vector<>();
139 mBroadcastReceiver = new BroadcastReceiver() {
140 @Override
141 public void onReceive(Context context, Intent intent) {
142 mIntents.addElement(intent);
143 }
144 };
145 mServiceContext.registerReceiver(mBroadcastReceiver,
146 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Kline5f2b7992017-03-10 19:35:34 +0900147 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Christopher Wiley497c1472016-10-11 13:26:03 -0700148 mLooper.getLooper(), mSystemProperties);
149 }
150
Erik Kline668b7222017-04-17 16:47:23 +0900151 @After
152 public void tearDown() {
153 mServiceContext.unregisterReceiver(mBroadcastReceiver);
154 }
155
Christopher Wiley497c1472016-10-11 13:26:03 -0700156 private void setupForRequiredProvisioning() {
157 // Produce some acceptable looking provision app setting if requested.
158 when(mResources.getStringArray(
159 com.android.internal.R.array.config_mobile_hotspot_provision_app))
160 .thenReturn(PROVISIONING_APP_NAME);
161 // Don't disable tethering provisioning unless requested.
162 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
163 anyBoolean())).thenReturn(false);
164 // Act like the CarrierConfigManager is present and ready unless told otherwise.
165 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
166 .thenReturn(mCarrierConfigManager);
167 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
168 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
169 }
170
171 @Test
172 public void canRequireProvisioning() {
173 setupForRequiredProvisioning();
174 assertTrue(mTethering.isTetherProvisioningRequired());
175 }
176
177 @Test
178 public void toleratesCarrierConfigManagerMissing() {
179 setupForRequiredProvisioning();
180 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
181 .thenReturn(null);
182 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
183 // We therefore still require provisioning.
184 assertTrue(mTethering.isTetherProvisioningRequired());
185 }
186
187 @Test
188 public void toleratesCarrierConfigMissing() {
189 setupForRequiredProvisioning();
190 when(mCarrierConfigManager.getConfig()).thenReturn(null);
191 // We still have a provisioning app configured, so still require provisioning.
192 assertTrue(mTethering.isTetherProvisioningRequired());
193 }
194
195 @Test
196 public void provisioningNotRequiredWhenAppNotFound() {
197 setupForRequiredProvisioning();
198 when(mResources.getStringArray(
199 com.android.internal.R.array.config_mobile_hotspot_provision_app))
200 .thenReturn(null);
201 assertTrue(!mTethering.isTetherProvisioningRequired());
202 when(mResources.getStringArray(
203 com.android.internal.R.array.config_mobile_hotspot_provision_app))
204 .thenReturn(new String[] {"malformedApp"});
205 assertTrue(!mTethering.isTetherProvisioningRequired());
206 }
Erik Kline5f2b7992017-03-10 19:35:34 +0900207
208 private void sendWifiApStateChanged(int state) {
209 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
Erik Kline1454ee72017-05-31 15:53:53 +0900210 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
Erik Kline5f2b7992017-03-10 19:35:34 +0900211 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
212 }
213
Erik Kline1454ee72017-05-31 15:53:53 +0900214 private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
215 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
216 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
217 intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
218 intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
219 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
220 }
221
Erik Kline9e225542017-06-08 17:48:48 +0900222 private void verifyInterfaceServingModeStarted() throws Exception {
Erik Kline668b7222017-04-17 16:47:23 +0900223 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
224 verify(mNMService, times(1))
225 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
226 verify(mNMService, times(1)).tetherInterface(mTestIfname);
227 }
228
229 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
230 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
231 final Intent bcast = mIntents.get(0);
232 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
233 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
234 assertTrue(ifnames.contains(ifname));
235 mIntents.remove(bcast);
236 }
237
Erik Kline9e225542017-06-08 17:48:48 +0900238 @Test
239 public void failingLocalOnlyHotspotLegacyApBroadcast() throws Exception {
Erik Kline5f2b7992017-03-10 19:35:34 +0900240 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Kline5f2b7992017-03-10 19:35:34 +0900241
242 // Emulate externally-visible WifiManager effects, causing the
243 // per-interface state machine to start up, and telling us that
244 // hotspot mode is to be started.
245 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900246 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Kline5f2b7992017-03-10 19:35:34 +0900247 mLooper.dispatchAll();
248
Erik Kline9e225542017-06-08 17:48:48 +0900249 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
250 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
251 verifyNoMoreInteractions(mConnectivityManager);
252 verifyNoMoreInteractions(mNMService);
253 verifyNoMoreInteractions(mWifiManager);
254 }
255
256 @Test
257 public void workingLocalOnlyHotspotEnrichedApBroadcast() throws Exception {
258 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
259
260 // Emulate externally-visible WifiManager effects, causing the
261 // per-interface state machine to start up, and telling us that
262 // hotspot mode is to be started.
263 mTethering.interfaceStatusChanged(mTestIfname, true);
264 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
265 mLooper.dispatchAll();
266
267 verifyInterfaceServingModeStarted();
Erik Kline668b7222017-04-17 16:47:23 +0900268 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Kline5f2b7992017-03-10 19:35:34 +0900269 verify(mNMService, times(1)).setIpForwardingEnabled(true);
270 verify(mNMService, times(1)).startTethering(any(String[].class));
271 verifyNoMoreInteractions(mNMService);
Erik Kline080f9732017-04-27 20:57:23 +0900272 verify(mWifiManager).updateInterfaceIpState(
273 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
274 verifyNoMoreInteractions(mWifiManager);
Erik Kline668b7222017-04-17 16:47:23 +0900275 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Kline5f2b7992017-03-10 19:35:34 +0900276 // UpstreamNetworkMonitor will be started, and will register two callbacks:
277 // a "listen all" and a "track default".
278 verify(mConnectivityManager, times(1)).registerNetworkCallback(
279 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
280 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
281 any(NetworkCallback.class), any(Handler.class));
282 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
283 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
284 verifyNoMoreInteractions(mConnectivityManager);
285
286 // Emulate externally-visible WifiManager effects, when hotspot mode
287 // is being torn down.
288 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
289 mTethering.interfaceRemoved(mTestIfname);
290 mLooper.dispatchAll();
291
292 verify(mNMService, times(1)).untetherInterface(mTestIfname);
293 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
294 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
295 verify(mNMService, atLeastOnce())
296 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
297 verify(mNMService, times(1)).stopTethering();
298 verify(mNMService, times(1)).setIpForwardingEnabled(false);
299 verifyNoMoreInteractions(mNMService);
Erik Kline080f9732017-04-27 20:57:23 +0900300 verifyNoMoreInteractions(mWifiManager);
Erik Kline5f2b7992017-03-10 19:35:34 +0900301 // Asking for the last error after the per-interface state machine
302 // has been reaped yields an unknown interface error.
303 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
304 mTethering.getLastTetherError(mTestIfname));
305 }
306
307 @Test
Erik Kline9e225542017-06-08 17:48:48 +0900308 public void failingWifiTetheringLegacyApBroadcast() throws Exception {
Erik Kline5f2b7992017-03-10 19:35:34 +0900309 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Kline413190b2017-04-18 14:22:25 +0900310 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Kline5f2b7992017-03-10 19:35:34 +0900311
312 // Emulate pressing the WiFi tethering button.
313 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
314 mLooper.dispatchAll();
Erik Kline413190b2017-04-18 14:22:25 +0900315 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Kline5f2b7992017-03-10 19:35:34 +0900316 verifyNoMoreInteractions(mWifiManager);
317 verifyNoMoreInteractions(mConnectivityManager);
318 verifyNoMoreInteractions(mNMService);
319
320 // Emulate externally-visible WifiManager effects, causing the
321 // per-interface state machine to start up, and telling us that
322 // tethering mode is to be started.
323 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900324 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Kline5f2b7992017-03-10 19:35:34 +0900325 mLooper.dispatchAll();
326
Erik Kline9e225542017-06-08 17:48:48 +0900327 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
328 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
329 verifyNoMoreInteractions(mConnectivityManager);
330 verifyNoMoreInteractions(mNMService);
331 verifyNoMoreInteractions(mWifiManager);
332 }
333
334 @Test
335 public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
336 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
337 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
338
339 // Emulate pressing the WiFi tethering button.
340 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
341 mLooper.dispatchAll();
342 verify(mWifiManager, times(1)).startSoftAp(null);
343 verifyNoMoreInteractions(mWifiManager);
344 verifyNoMoreInteractions(mConnectivityManager);
345 verifyNoMoreInteractions(mNMService);
346
347 // Emulate externally-visible WifiManager effects, causing the
348 // per-interface state machine to start up, and telling us that
349 // tethering mode is to be started.
350 mTethering.interfaceStatusChanged(mTestIfname, true);
351 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
352 mLooper.dispatchAll();
353
354 verifyInterfaceServingModeStarted();
Erik Kline668b7222017-04-17 16:47:23 +0900355 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Kline5f2b7992017-03-10 19:35:34 +0900356 verify(mNMService, times(1)).setIpForwardingEnabled(true);
357 verify(mNMService, times(1)).startTethering(any(String[].class));
358 verifyNoMoreInteractions(mNMService);
Erik Kline080f9732017-04-27 20:57:23 +0900359 verify(mWifiManager).updateInterfaceIpState(
360 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
361 verifyNoMoreInteractions(mWifiManager);
Erik Kline668b7222017-04-17 16:47:23 +0900362 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Kline5f2b7992017-03-10 19:35:34 +0900363 // UpstreamNetworkMonitor will be started, and will register two callbacks:
364 // a "listen all" and a "track default".
365 verify(mConnectivityManager, times(1)).registerNetworkCallback(
366 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
367 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
368 any(NetworkCallback.class), any(Handler.class));
369 // In tethering mode, in the default configuration, an explicit request
370 // for a mobile network is also made.
371 verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
372 verify(mConnectivityManager, times(1)).requestNetwork(
373 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
374 any(Handler.class));
375 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
376 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
377 verifyNoMoreInteractions(mConnectivityManager);
378
379 /////
380 // We do not currently emulate any upstream being found.
381 //
382 // This is why there are no calls to verify mNMService.enableNat() or
383 // mNMService.startInterfaceForwarding().
384 /////
385
386 // Emulate pressing the WiFi tethering button.
387 mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
388 mLooper.dispatchAll();
Erik Kline413190b2017-04-18 14:22:25 +0900389 verify(mWifiManager, times(1)).stopSoftAp();
Erik Kline5f2b7992017-03-10 19:35:34 +0900390 verifyNoMoreInteractions(mWifiManager);
391 verifyNoMoreInteractions(mConnectivityManager);
392 verifyNoMoreInteractions(mNMService);
393
394 // Emulate externally-visible WifiManager effects, when tethering mode
395 // is being torn down.
396 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
397 mTethering.interfaceRemoved(mTestIfname);
398 mLooper.dispatchAll();
399
400 verify(mNMService, times(1)).untetherInterface(mTestIfname);
401 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
402 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
403 verify(mNMService, atLeastOnce())
404 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
405 verify(mNMService, times(1)).stopTethering();
406 verify(mNMService, times(1)).setIpForwardingEnabled(false);
407 verifyNoMoreInteractions(mNMService);
Erik Kline080f9732017-04-27 20:57:23 +0900408 verifyNoMoreInteractions(mWifiManager);
Erik Kline5f2b7992017-03-10 19:35:34 +0900409 // Asking for the last error after the per-interface state machine
410 // has been reaped yields an unknown interface error.
411 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
412 mTethering.getLastTetherError(mTestIfname));
413 }
414
Erik Kline38356e92017-05-08 17:56:35 +0900415 @Test
416 public void failureEnablingIpForwarding() throws Exception {
417 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
418 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
419 doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
420
421 // Emulate pressing the WiFi tethering button.
422 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
423 mLooper.dispatchAll();
424 verify(mWifiManager, times(1)).startSoftAp(null);
425 verifyNoMoreInteractions(mWifiManager);
426 verifyNoMoreInteractions(mConnectivityManager);
427 verifyNoMoreInteractions(mNMService);
428
429 // Emulate externally-visible WifiManager effects, causing the
430 // per-interface state machine to start up, and telling us that
431 // tethering mode is to be started.
432 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900433 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
Erik Kline38356e92017-05-08 17:56:35 +0900434 mLooper.dispatchAll();
435
Erik Kline38356e92017-05-08 17:56:35 +0900436 // We verify get/set called twice here: once for setup and once during
437 // teardown because all events happen over the course of the single
438 // dispatchAll() above.
439 verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
440 verify(mNMService, times(2))
441 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
442 verify(mNMService, times(1)).tetherInterface(mTestIfname);
443 verify(mWifiManager).updateInterfaceIpState(
444 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
445 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
446 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
447 // This is called, but will throw.
448 verify(mNMService, times(1)).setIpForwardingEnabled(true);
449 // This never gets called because of the exception thrown above.
450 verify(mNMService, times(0)).startTethering(any(String[].class));
451 // When the master state machine transitions to an error state it tells
452 // downstream interfaces, which causes us to tell Wi-Fi about the error
453 // so it can take down AP mode.
454 verify(mNMService, times(1)).untetherInterface(mTestIfname);
455 verify(mWifiManager).updateInterfaceIpState(
456 mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
457
458 verifyNoMoreInteractions(mWifiManager);
459 verifyNoMoreInteractions(mConnectivityManager);
460 verifyNoMoreInteractions(mNMService);
461 }
462
463 // TODO: Test that a request for hotspot mode doesn't interfere with an
Erik Kline5f2b7992017-03-10 19:35:34 +0900464 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700465}