blob: a115146486a493849f9eb4874308a068199b98e2 [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;
43
Erik Kline8351faa2017-04-17 16:47:23 +090044import android.content.BroadcastReceiver;
Erik Kline92c4db02017-05-31 10:21:32 +090045import android.content.ContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070046import android.content.Context;
Erik Klineea9cc482017-03-10 19:35:34 +090047import android.content.ContextWrapper;
48import android.content.Intent;
Erik Kline8351faa2017-04-17 16:47:23 +090049import android.content.IntentFilter;
Erik Klinef3a08b42017-06-07 16:33:19 +090050import android.content.pm.ApplicationInfo;
Christopher Wiley497c1472016-10-11 13:26:03 -070051import android.content.res.Resources;
Erik Klineea9cc482017-03-10 19:35:34 +090052import android.hardware.usb.UsbManager;
53import android.net.ConnectivityManager;
54import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070055import android.net.INetworkPolicyManager;
56import android.net.INetworkStatsService;
Erik Klineea9cc482017-03-10 19:35:34 +090057import android.net.InterfaceConfiguration;
58import android.net.NetworkRequest;
Erik Klinef4b6e342017-04-25 19:19:59 +090059import android.net.util.SharedLog;
Erik Klineea9cc482017-03-10 19:35:34 +090060import android.net.wifi.WifiConfiguration;
61import android.net.wifi.WifiManager;
62import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070063import android.os.INetworkManagementService;
64import android.os.PersistableBundle;
Erik Kline1fdc2e22017-05-08 17:56:35 +090065import android.os.RemoteException;
Christopher Wiley497c1472016-10-11 13:26:03 -070066import android.os.test.TestLooper;
Erik Klineea9cc482017-03-10 19:35:34 +090067import android.os.UserHandle;
Erik Kline92c4db02017-05-31 10:21:32 +090068import android.provider.Settings;
Christopher Wiley497c1472016-10-11 13:26:03 -070069import android.support.test.filters.SmallTest;
70import android.support.test.runner.AndroidJUnit4;
71import android.telephony.CarrierConfigManager;
Erik Kline92c4db02017-05-31 10:21:32 +090072import android.test.mock.MockContentResolver;
Christopher Wiley497c1472016-10-11 13:26:03 -070073
Erik Klineea9cc482017-03-10 19:35:34 +090074import com.android.internal.util.test.BroadcastInterceptingContext;
Erik Kline92c4db02017-05-31 10:21:32 +090075import com.android.internal.util.test.FakeSettingsProvider;
Erik Kline5a7c8a02017-04-30 19:36:15 +090076import com.android.server.connectivity.tethering.OffloadHardwareInterface;
77import com.android.server.connectivity.tethering.TetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +090078
Erik Kline8351faa2017-04-17 16:47:23 +090079import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070080import org.junit.Before;
81import org.junit.Test;
82import org.junit.runner.RunWith;
83import org.mockito.Mock;
84import org.mockito.MockitoAnnotations;
85
Erik Kline8351faa2017-04-17 16:47:23 +090086import java.util.ArrayList;
87import java.util.Vector;
88
Christopher Wiley497c1472016-10-11 13:26:03 -070089@RunWith(AndroidJUnit4.class)
90@SmallTest
91public class TetheringTest {
92 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
93
Erik Klinef3a08b42017-06-07 16:33:19 +090094 @Mock private ApplicationInfo mApplicationInfo;
Christopher Wiley497c1472016-10-11 13:26:03 -070095 @Mock private Context mContext;
Erik Klineea9cc482017-03-10 19:35:34 +090096 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070097 @Mock private INetworkManagementService mNMService;
98 @Mock private INetworkStatsService mStatsService;
99 @Mock private INetworkPolicyManager mPolicyManager;
100 @Mock private MockableSystemProperties mSystemProperties;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900101 @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
Christopher Wiley497c1472016-10-11 13:26:03 -0700102 @Mock private Resources mResources;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900103 @Mock private TetheringDependencies mTetheringDependencies;
Erik Klineea9cc482017-03-10 19:35:34 +0900104 @Mock private UsbManager mUsbManager;
105 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -0700106 @Mock private CarrierConfigManager mCarrierConfigManager;
107
108 // Like so many Android system APIs, these cannot be mocked because it is marked final.
109 // We have to use the real versions.
110 private final PersistableBundle mCarrierConfig = new PersistableBundle();
111 private final TestLooper mLooper = new TestLooper();
Erik Klineea9cc482017-03-10 19:35:34 +0900112 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -0700113
Erik Kline8351faa2017-04-17 16:47:23 +0900114 private Vector<Intent> mIntents;
Erik Klineea9cc482017-03-10 19:35:34 +0900115 private BroadcastInterceptingContext mServiceContext;
Erik Kline92c4db02017-05-31 10:21:32 +0900116 private MockContentResolver mContentResolver;
Erik Kline8351faa2017-04-17 16:47:23 +0900117 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -0700118 private Tethering mTethering;
119
Erik Klineea9cc482017-03-10 19:35:34 +0900120 private class MockContext extends BroadcastInterceptingContext {
121 MockContext(Context base) {
122 super(base);
123 }
124
125 @Override
Erik Klinef3a08b42017-06-07 16:33:19 +0900126 public ApplicationInfo getApplicationInfo() { return mApplicationInfo; }
127
128 @Override
Erik Kline92c4db02017-05-31 10:21:32 +0900129 public ContentResolver getContentResolver() { return mContentResolver; }
130
131 @Override
132 public String getPackageName() { return "TetheringTest"; }
133
134 @Override
Erik Klineea9cc482017-03-10 19:35:34 +0900135 public Resources getResources() { return mResources; }
136
137 @Override
138 public Object getSystemService(String name) {
139 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
140 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
Erik Klinec438e302017-07-04 22:02:49 +0900141 if (Context.USB_SERVICE.equals(name)) return mUsbManager;
Erik Klineea9cc482017-03-10 19:35:34 +0900142 return super.getSystemService(name);
143 }
144 }
145
Erik Kline8351faa2017-04-17 16:47:23 +0900146 @Before
147 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700148 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700149 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
150 .thenReturn(new String[0]);
151 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
152 .thenReturn(new String[0]);
153 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Klinec438e302017-07-04 22:02:49 +0900154 .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700155 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
156 .thenReturn(new String[0]);
157 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
158 .thenReturn(new int[0]);
Erik Klineea9cc482017-03-10 19:35:34 +0900159 when(mNMService.listInterfaces())
160 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
161 when(mNMService.getInterfaceConfig(anyString()))
162 .thenReturn(new InterfaceConfiguration());
163
164 mServiceContext = new MockContext(mContext);
Erik Kline92c4db02017-05-31 10:21:32 +0900165 mContentResolver = new MockContentResolver(mServiceContext);
166 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline8351faa2017-04-17 16:47:23 +0900167 mIntents = new Vector<>();
168 mBroadcastReceiver = new BroadcastReceiver() {
169 @Override
170 public void onReceive(Context context, Intent intent) {
171 mIntents.addElement(intent);
172 }
173 };
174 mServiceContext.registerReceiver(mBroadcastReceiver,
175 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Klinef4b6e342017-04-25 19:19:59 +0900176 when(mTetheringDependencies.getOffloadHardwareInterface(
177 any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
Erik Klineea9cc482017-03-10 19:35:34 +0900178 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Erik Kline5a7c8a02017-04-30 19:36:15 +0900179 mLooper.getLooper(), mSystemProperties,
180 mTetheringDependencies);
Lorenzo Colitti5a7dea12017-07-12 15:48:07 +0900181 verify(mNMService).registerTetheringStatsProvider(any(), anyString());
Christopher Wiley497c1472016-10-11 13:26:03 -0700182 }
183
Erik Kline8351faa2017-04-17 16:47:23 +0900184 @After
185 public void tearDown() {
186 mServiceContext.unregisterReceiver(mBroadcastReceiver);
187 }
188
Christopher Wiley497c1472016-10-11 13:26:03 -0700189 private void setupForRequiredProvisioning() {
190 // Produce some acceptable looking provision app setting if requested.
191 when(mResources.getStringArray(
192 com.android.internal.R.array.config_mobile_hotspot_provision_app))
193 .thenReturn(PROVISIONING_APP_NAME);
194 // Don't disable tethering provisioning unless requested.
195 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
196 anyBoolean())).thenReturn(false);
197 // Act like the CarrierConfigManager is present and ready unless told otherwise.
198 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
199 .thenReturn(mCarrierConfigManager);
200 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
201 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
202 }
203
204 @Test
205 public void canRequireProvisioning() {
206 setupForRequiredProvisioning();
207 assertTrue(mTethering.isTetherProvisioningRequired());
208 }
209
210 @Test
211 public void toleratesCarrierConfigManagerMissing() {
212 setupForRequiredProvisioning();
213 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
214 .thenReturn(null);
215 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
216 // We therefore still require provisioning.
217 assertTrue(mTethering.isTetherProvisioningRequired());
218 }
219
220 @Test
221 public void toleratesCarrierConfigMissing() {
222 setupForRequiredProvisioning();
223 when(mCarrierConfigManager.getConfig()).thenReturn(null);
224 // We still have a provisioning app configured, so still require provisioning.
225 assertTrue(mTethering.isTetherProvisioningRequired());
226 }
227
228 @Test
229 public void provisioningNotRequiredWhenAppNotFound() {
230 setupForRequiredProvisioning();
231 when(mResources.getStringArray(
232 com.android.internal.R.array.config_mobile_hotspot_provision_app))
233 .thenReturn(null);
234 assertTrue(!mTethering.isTetherProvisioningRequired());
235 when(mResources.getStringArray(
236 com.android.internal.R.array.config_mobile_hotspot_provision_app))
237 .thenReturn(new String[] {"malformedApp"});
238 assertTrue(!mTethering.isTetherProvisioningRequired());
239 }
Erik Klineea9cc482017-03-10 19:35:34 +0900240
241 private void sendWifiApStateChanged(int state) {
242 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
Erik Kline2efb8272017-05-31 15:53:53 +0900243 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
Erik Klineea9cc482017-03-10 19:35:34 +0900244 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
245 }
246
Erik Kline2efb8272017-05-31 15:53:53 +0900247 private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
248 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
249 intent.putExtra(EXTRA_WIFI_AP_STATE, state);
250 intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
251 intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
252 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
253 }
254
Erik Klinec438e302017-07-04 22:02:49 +0900255 private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
256 final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
257 intent.putExtra(USB_CONNECTED, connected);
258 intent.putExtra(USB_CONFIGURED, configured);
259 intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
260 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
261 }
262
Erik Kline9e225542017-06-08 17:48:48 +0900263 private void verifyInterfaceServingModeStarted() throws Exception {
Erik Kline8351faa2017-04-17 16:47:23 +0900264 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
265 verify(mNMService, times(1))
266 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
267 verify(mNMService, times(1)).tetherInterface(mTestIfname);
268 }
269
270 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
271 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
272 final Intent bcast = mIntents.get(0);
273 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
274 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
275 assertTrue(ifnames.contains(ifname));
276 mIntents.remove(bcast);
277 }
278
Erik Klinea9cde8b2017-06-20 21:18:31 +0900279 public void failingLocalOnlyHotspotLegacyApBroadcast(
280 boolean emulateInterfaceStatusChanged) throws Exception {
Erik Klineea9cc482017-03-10 19:35:34 +0900281 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900282
283 // Emulate externally-visible WifiManager effects, causing the
284 // per-interface state machine to start up, and telling us that
285 // hotspot mode is to be started.
Erik Klinea9cde8b2017-06-20 21:18:31 +0900286 if (emulateInterfaceStatusChanged) {
287 mTethering.interfaceStatusChanged(mTestIfname, true);
288 }
Erik Kline9e225542017-06-08 17:48:48 +0900289 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Klineea9cc482017-03-10 19:35:34 +0900290 mLooper.dispatchAll();
291
Erik Klinea9cde8b2017-06-20 21:18:31 +0900292 // If, and only if, Tethering received an interface status changed
293 // then it creates a TetherInterfaceStateMachine and sends out a
294 // broadcast indicating that the interface is "available".
295 if (emulateInterfaceStatusChanged) {
296 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
297 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
298 }
Erik Kline9e225542017-06-08 17:48:48 +0900299 verifyNoMoreInteractions(mConnectivityManager);
300 verifyNoMoreInteractions(mNMService);
301 verifyNoMoreInteractions(mWifiManager);
302 }
303
304 @Test
Erik Klinec438e302017-07-04 22:02:49 +0900305 public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
306 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
307
308 // Emulate pressing the USB tethering button in Settings UI.
309 mTethering.startTethering(TETHERING_USB, null, false);
310 mLooper.dispatchAll();
311 verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
312
313 // Pretend we receive a USB connected broadcast. Here we also pretend
314 // that the RNDIS function is somehow enabled, so that we see if we
315 // might trip ourselves up.
316 sendUsbBroadcast(true, false, true);
317 mLooper.dispatchAll();
318 // This should produce no activity of any kind.
319 verifyNoMoreInteractions(mConnectivityManager);
320 verifyNoMoreInteractions(mNMService);
321
322 // Pretend we then receive USB configured broadcast.
323 sendUsbBroadcast(true, true, true);
324 mLooper.dispatchAll();
325 // Now we should see the start of tethering mechanics (in this case:
326 // tetherMatchingInterfaces() which starts by fetching all interfaces).
327 verify(mNMService, times(1)).listInterfaces();
328 }
329
330 @Test
Erik Klinea9cde8b2017-06-20 21:18:31 +0900331 public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
332 failingLocalOnlyHotspotLegacyApBroadcast(true);
333 }
334
335 @Test
336 public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
337 failingLocalOnlyHotspotLegacyApBroadcast(false);
338 }
339
340 public void workingLocalOnlyHotspotEnrichedApBroadcast(
341 boolean emulateInterfaceStatusChanged) throws Exception {
Erik Kline9e225542017-06-08 17:48:48 +0900342 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
343
344 // Emulate externally-visible WifiManager effects, causing the
345 // per-interface state machine to start up, and telling us that
346 // hotspot mode is to be started.
Erik Klinea9cde8b2017-06-20 21:18:31 +0900347 if (emulateInterfaceStatusChanged) {
348 mTethering.interfaceStatusChanged(mTestIfname, true);
349 }
Erik Kline9e225542017-06-08 17:48:48 +0900350 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
351 mLooper.dispatchAll();
352
353 verifyInterfaceServingModeStarted();
Erik Kline8351faa2017-04-17 16:47:23 +0900354 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900355 verify(mNMService, times(1)).setIpForwardingEnabled(true);
356 verify(mNMService, times(1)).startTethering(any(String[].class));
357 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900358 verify(mWifiManager).updateInterfaceIpState(
359 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
360 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900361 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900362 // UpstreamNetworkMonitor will be started, and will register two callbacks:
363 // a "listen all" and a "track default".
364 verify(mConnectivityManager, times(1)).registerNetworkCallback(
365 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
366 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
367 any(NetworkCallback.class), any(Handler.class));
368 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
369 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
370 verifyNoMoreInteractions(mConnectivityManager);
371
372 // Emulate externally-visible WifiManager effects, when hotspot mode
373 // is being torn down.
374 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
375 mTethering.interfaceRemoved(mTestIfname);
376 mLooper.dispatchAll();
377
378 verify(mNMService, times(1)).untetherInterface(mTestIfname);
379 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
380 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
381 verify(mNMService, atLeastOnce())
382 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
383 verify(mNMService, times(1)).stopTethering();
384 verify(mNMService, times(1)).setIpForwardingEnabled(false);
385 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900386 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900387 // Asking for the last error after the per-interface state machine
388 // has been reaped yields an unknown interface error.
389 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
390 mTethering.getLastTetherError(mTestIfname));
391 }
392
393 @Test
Erik Klinea9cde8b2017-06-20 21:18:31 +0900394 public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
395 workingLocalOnlyHotspotEnrichedApBroadcast(true);
396 }
397
398 @Test
399 public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
400 workingLocalOnlyHotspotEnrichedApBroadcast(false);
401 }
402
403 // TODO: Test with and without interfaceStatusChanged().
404 @Test
Erik Kline9e225542017-06-08 17:48:48 +0900405 public void failingWifiTetheringLegacyApBroadcast() throws Exception {
Erik Klineea9cc482017-03-10 19:35:34 +0900406 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineceb54c62017-04-18 14:22:25 +0900407 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900408
409 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900410 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Klineea9cc482017-03-10 19:35:34 +0900411 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900412 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Klineea9cc482017-03-10 19:35:34 +0900413 verifyNoMoreInteractions(mWifiManager);
414 verifyNoMoreInteractions(mConnectivityManager);
415 verifyNoMoreInteractions(mNMService);
416
417 // Emulate externally-visible WifiManager effects, causing the
418 // per-interface state machine to start up, and telling us that
419 // tethering mode is to be started.
420 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900421 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
Erik Klineea9cc482017-03-10 19:35:34 +0900422 mLooper.dispatchAll();
423
Erik Kline9e225542017-06-08 17:48:48 +0900424 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
425 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
426 verifyNoMoreInteractions(mConnectivityManager);
427 verifyNoMoreInteractions(mNMService);
428 verifyNoMoreInteractions(mWifiManager);
429 }
430
Erik Klinea9cde8b2017-06-20 21:18:31 +0900431 // TODO: Test with and without interfaceStatusChanged().
Erik Kline9e225542017-06-08 17:48:48 +0900432 @Test
433 public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
434 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
435 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
436
437 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900438 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Kline9e225542017-06-08 17:48:48 +0900439 mLooper.dispatchAll();
440 verify(mWifiManager, times(1)).startSoftAp(null);
441 verifyNoMoreInteractions(mWifiManager);
442 verifyNoMoreInteractions(mConnectivityManager);
443 verifyNoMoreInteractions(mNMService);
444
445 // Emulate externally-visible WifiManager effects, causing the
446 // per-interface state machine to start up, and telling us that
447 // tethering mode is to be started.
448 mTethering.interfaceStatusChanged(mTestIfname, true);
449 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
450 mLooper.dispatchAll();
451
452 verifyInterfaceServingModeStarted();
Erik Kline8351faa2017-04-17 16:47:23 +0900453 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900454 verify(mNMService, times(1)).setIpForwardingEnabled(true);
455 verify(mNMService, times(1)).startTethering(any(String[].class));
456 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900457 verify(mWifiManager).updateInterfaceIpState(
458 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
459 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900460 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900461 // UpstreamNetworkMonitor will be started, and will register two callbacks:
462 // a "listen all" and a "track default".
463 verify(mConnectivityManager, times(1)).registerNetworkCallback(
464 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
465 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
466 any(NetworkCallback.class), any(Handler.class));
467 // In tethering mode, in the default configuration, an explicit request
468 // for a mobile network is also made.
Erik Klineea9cc482017-03-10 19:35:34 +0900469 verify(mConnectivityManager, times(1)).requestNetwork(
470 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
471 any(Handler.class));
472 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
473 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
474 verifyNoMoreInteractions(mConnectivityManager);
475
476 /////
477 // We do not currently emulate any upstream being found.
478 //
479 // This is why there are no calls to verify mNMService.enableNat() or
480 // mNMService.startInterfaceForwarding().
481 /////
482
483 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900484 mTethering.stopTethering(TETHERING_WIFI);
Erik Klineea9cc482017-03-10 19:35:34 +0900485 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900486 verify(mWifiManager, times(1)).stopSoftAp();
Erik Klineea9cc482017-03-10 19:35:34 +0900487 verifyNoMoreInteractions(mWifiManager);
488 verifyNoMoreInteractions(mConnectivityManager);
489 verifyNoMoreInteractions(mNMService);
490
491 // Emulate externally-visible WifiManager effects, when tethering mode
492 // is being torn down.
493 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
494 mTethering.interfaceRemoved(mTestIfname);
495 mLooper.dispatchAll();
496
497 verify(mNMService, times(1)).untetherInterface(mTestIfname);
498 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
499 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
500 verify(mNMService, atLeastOnce())
501 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
502 verify(mNMService, times(1)).stopTethering();
503 verify(mNMService, times(1)).setIpForwardingEnabled(false);
504 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900505 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900506 // Asking for the last error after the per-interface state machine
507 // has been reaped yields an unknown interface error.
508 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
509 mTethering.getLastTetherError(mTestIfname));
510 }
511
Erik Klinea9cde8b2017-06-20 21:18:31 +0900512 // TODO: Test with and without interfaceStatusChanged().
Erik Kline1fdc2e22017-05-08 17:56:35 +0900513 @Test
514 public void failureEnablingIpForwarding() throws Exception {
515 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
516 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
517 doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
518
519 // Emulate pressing the WiFi tethering button.
Erik Klinec438e302017-07-04 22:02:49 +0900520 mTethering.startTethering(TETHERING_WIFI, null, false);
Erik Kline1fdc2e22017-05-08 17:56:35 +0900521 mLooper.dispatchAll();
522 verify(mWifiManager, times(1)).startSoftAp(null);
523 verifyNoMoreInteractions(mWifiManager);
524 verifyNoMoreInteractions(mConnectivityManager);
525 verifyNoMoreInteractions(mNMService);
526
527 // Emulate externally-visible WifiManager effects, causing the
528 // per-interface state machine to start up, and telling us that
529 // tethering mode is to be started.
530 mTethering.interfaceStatusChanged(mTestIfname, true);
Erik Kline9e225542017-06-08 17:48:48 +0900531 sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
Erik Kline1fdc2e22017-05-08 17:56:35 +0900532 mLooper.dispatchAll();
533
Erik Kline1fdc2e22017-05-08 17:56:35 +0900534 // We verify get/set called twice here: once for setup and once during
535 // teardown because all events happen over the course of the single
536 // dispatchAll() above.
537 verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
538 verify(mNMService, times(2))
539 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
540 verify(mNMService, times(1)).tetherInterface(mTestIfname);
541 verify(mWifiManager).updateInterfaceIpState(
542 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
543 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
544 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
545 // This is called, but will throw.
546 verify(mNMService, times(1)).setIpForwardingEnabled(true);
547 // This never gets called because of the exception thrown above.
548 verify(mNMService, times(0)).startTethering(any(String[].class));
549 // When the master state machine transitions to an error state it tells
550 // downstream interfaces, which causes us to tell Wi-Fi about the error
551 // so it can take down AP mode.
552 verify(mNMService, times(1)).untetherInterface(mTestIfname);
553 verify(mWifiManager).updateInterfaceIpState(
554 mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
555
556 verifyNoMoreInteractions(mWifiManager);
557 verifyNoMoreInteractions(mConnectivityManager);
558 verifyNoMoreInteractions(mNMService);
559 }
560
561 // TODO: Test that a request for hotspot mode doesn't interfere with an
Erik Klineea9cc482017-03-10 19:35:34 +0900562 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700563}