blob: 7a1c2395c438e8f97270bbfd16dec243e6fd1b1f [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;
Erik Klineea9cc482017-03-10 19:35:34 +090021import static org.mockito.Mockito.any;
Christopher Wiley497c1472016-10-11 13:26:03 -070022import static org.mockito.Matchers.anyBoolean;
Erik Klineea9cc482017-03-10 19:35:34 +090023import static org.mockito.Matchers.anyInt;
24import static org.mockito.Matchers.anyString;
Christopher Wiley497c1472016-10-11 13:26:03 -070025import static org.mockito.Matchers.eq;
Erik Klineea9cc482017-03-10 19:35:34 +090026import static org.mockito.Mockito.atLeastOnce;
27import static org.mockito.Mockito.times;
28import static org.mockito.Mockito.verify;
29import static org.mockito.Mockito.verifyNoMoreInteractions;
Christopher Wiley497c1472016-10-11 13:26:03 -070030import static org.mockito.Mockito.when;
31
Erik Kline8351faa2017-04-17 16:47:23 +090032import android.content.BroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -070033import android.content.Context;
Erik Klineea9cc482017-03-10 19:35:34 +090034import android.content.ContextWrapper;
35import android.content.Intent;
Erik Kline8351faa2017-04-17 16:47:23 +090036import android.content.IntentFilter;
Christopher Wiley497c1472016-10-11 13:26:03 -070037import android.content.res.Resources;
Erik Klineea9cc482017-03-10 19:35:34 +090038import android.hardware.usb.UsbManager;
39import android.net.ConnectivityManager;
40import android.net.ConnectivityManager.NetworkCallback;
Christopher Wiley497c1472016-10-11 13:26:03 -070041import android.net.INetworkPolicyManager;
42import android.net.INetworkStatsService;
Erik Klineea9cc482017-03-10 19:35:34 +090043import android.net.InterfaceConfiguration;
44import android.net.NetworkRequest;
45import android.net.wifi.WifiConfiguration;
46import android.net.wifi.WifiManager;
47import android.os.Handler;
Christopher Wiley497c1472016-10-11 13:26:03 -070048import android.os.INetworkManagementService;
49import android.os.PersistableBundle;
50import android.os.test.TestLooper;
Erik Klineea9cc482017-03-10 19:35:34 +090051import android.os.UserHandle;
Christopher Wiley497c1472016-10-11 13:26:03 -070052import android.support.test.filters.SmallTest;
53import android.support.test.runner.AndroidJUnit4;
54import android.telephony.CarrierConfigManager;
55
Erik Klineea9cc482017-03-10 19:35:34 +090056import com.android.internal.util.test.BroadcastInterceptingContext;
57
Erik Kline8351faa2017-04-17 16:47:23 +090058import org.junit.After;
Christopher Wiley497c1472016-10-11 13:26:03 -070059import org.junit.Before;
60import org.junit.Test;
61import org.junit.runner.RunWith;
62import org.mockito.Mock;
63import org.mockito.MockitoAnnotations;
64
Erik Kline8351faa2017-04-17 16:47:23 +090065import java.util.ArrayList;
66import java.util.Vector;
67
Christopher Wiley497c1472016-10-11 13:26:03 -070068@RunWith(AndroidJUnit4.class)
69@SmallTest
70public class TetheringTest {
71 private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
72
73 @Mock private Context mContext;
Erik Klineea9cc482017-03-10 19:35:34 +090074 @Mock private ConnectivityManager mConnectivityManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070075 @Mock private INetworkManagementService mNMService;
76 @Mock private INetworkStatsService mStatsService;
77 @Mock private INetworkPolicyManager mPolicyManager;
78 @Mock private MockableSystemProperties mSystemProperties;
79 @Mock private Resources mResources;
Erik Klineea9cc482017-03-10 19:35:34 +090080 @Mock private UsbManager mUsbManager;
81 @Mock private WifiManager mWifiManager;
Christopher Wiley497c1472016-10-11 13:26:03 -070082 @Mock private CarrierConfigManager mCarrierConfigManager;
83
84 // Like so many Android system APIs, these cannot be mocked because it is marked final.
85 // We have to use the real versions.
86 private final PersistableBundle mCarrierConfig = new PersistableBundle();
87 private final TestLooper mLooper = new TestLooper();
Erik Klineea9cc482017-03-10 19:35:34 +090088 private final String mTestIfname = "test_wlan0";
Christopher Wiley497c1472016-10-11 13:26:03 -070089
Erik Kline8351faa2017-04-17 16:47:23 +090090 private Vector<Intent> mIntents;
Erik Klineea9cc482017-03-10 19:35:34 +090091 private BroadcastInterceptingContext mServiceContext;
Erik Kline8351faa2017-04-17 16:47:23 +090092 private BroadcastReceiver mBroadcastReceiver;
Christopher Wiley497c1472016-10-11 13:26:03 -070093 private Tethering mTethering;
94
Erik Klineea9cc482017-03-10 19:35:34 +090095 private class MockContext extends BroadcastInterceptingContext {
96 MockContext(Context base) {
97 super(base);
98 }
99
100 @Override
101 public Resources getResources() { return mResources; }
102
103 @Override
104 public Object getSystemService(String name) {
105 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
106 if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
107 return super.getSystemService(name);
108 }
109 }
110
Erik Kline8351faa2017-04-17 16:47:23 +0900111 @Before
112 public void setUp() throws Exception {
Christopher Wiley497c1472016-10-11 13:26:03 -0700113 MockitoAnnotations.initMocks(this);
Christopher Wiley497c1472016-10-11 13:26:03 -0700114 when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
115 .thenReturn(new String[0]);
116 when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
117 .thenReturn(new String[0]);
118 when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
Erik Klineea9cc482017-03-10 19:35:34 +0900119 .thenReturn(new String[]{ "test_wlan\\d" });
Christopher Wiley497c1472016-10-11 13:26:03 -0700120 when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
121 .thenReturn(new String[0]);
122 when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
123 .thenReturn(new int[0]);
Erik Klineea9cc482017-03-10 19:35:34 +0900124 when(mNMService.listInterfaces())
125 .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
126 when(mNMService.getInterfaceConfig(anyString()))
127 .thenReturn(new InterfaceConfiguration());
128
129 mServiceContext = new MockContext(mContext);
Erik Kline8351faa2017-04-17 16:47:23 +0900130 mIntents = new Vector<>();
131 mBroadcastReceiver = new BroadcastReceiver() {
132 @Override
133 public void onReceive(Context context, Intent intent) {
134 mIntents.addElement(intent);
135 }
136 };
137 mServiceContext.registerReceiver(mBroadcastReceiver,
138 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
Erik Klineea9cc482017-03-10 19:35:34 +0900139 mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
Christopher Wiley497c1472016-10-11 13:26:03 -0700140 mLooper.getLooper(), mSystemProperties);
141 }
142
Erik Kline8351faa2017-04-17 16:47:23 +0900143 @After
144 public void tearDown() {
145 mServiceContext.unregisterReceiver(mBroadcastReceiver);
146 }
147
Christopher Wiley497c1472016-10-11 13:26:03 -0700148 private void setupForRequiredProvisioning() {
149 // Produce some acceptable looking provision app setting if requested.
150 when(mResources.getStringArray(
151 com.android.internal.R.array.config_mobile_hotspot_provision_app))
152 .thenReturn(PROVISIONING_APP_NAME);
153 // Don't disable tethering provisioning unless requested.
154 when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
155 anyBoolean())).thenReturn(false);
156 // Act like the CarrierConfigManager is present and ready unless told otherwise.
157 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
158 .thenReturn(mCarrierConfigManager);
159 when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
160 mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
161 }
162
163 @Test
164 public void canRequireProvisioning() {
165 setupForRequiredProvisioning();
166 assertTrue(mTethering.isTetherProvisioningRequired());
167 }
168
169 @Test
170 public void toleratesCarrierConfigManagerMissing() {
171 setupForRequiredProvisioning();
172 when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
173 .thenReturn(null);
174 // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
175 // We therefore still require provisioning.
176 assertTrue(mTethering.isTetherProvisioningRequired());
177 }
178
179 @Test
180 public void toleratesCarrierConfigMissing() {
181 setupForRequiredProvisioning();
182 when(mCarrierConfigManager.getConfig()).thenReturn(null);
183 // We still have a provisioning app configured, so still require provisioning.
184 assertTrue(mTethering.isTetherProvisioningRequired());
185 }
186
187 @Test
188 public void provisioningNotRequiredWhenAppNotFound() {
189 setupForRequiredProvisioning();
190 when(mResources.getStringArray(
191 com.android.internal.R.array.config_mobile_hotspot_provision_app))
192 .thenReturn(null);
193 assertTrue(!mTethering.isTetherProvisioningRequired());
194 when(mResources.getStringArray(
195 com.android.internal.R.array.config_mobile_hotspot_provision_app))
196 .thenReturn(new String[] {"malformedApp"});
197 assertTrue(!mTethering.isTetherProvisioningRequired());
198 }
Erik Klineea9cc482017-03-10 19:35:34 +0900199
200 private void sendWifiApStateChanged(int state) {
201 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
202 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, state);
203 mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
204 }
205
Erik Kline8351faa2017-04-17 16:47:23 +0900206 private void verifyInterfaceServingModeStarted() throws Exception {
207 verify(mNMService, times(1)).listInterfaces();
208 verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
209 verify(mNMService, times(1))
210 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
211 verify(mNMService, times(1)).tetherInterface(mTestIfname);
212 }
213
214 private void verifyTetheringBroadcast(String ifname, String whichExtra) {
215 // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
216 final Intent bcast = mIntents.get(0);
217 assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
218 final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
219 assertTrue(ifnames.contains(ifname));
220 mIntents.remove(bcast);
221 }
222
Erik Klineea9cc482017-03-10 19:35:34 +0900223 @Test
224 public void workingLocalOnlyHotspot() throws Exception {
225 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900226
227 // Emulate externally-visible WifiManager effects, causing the
228 // per-interface state machine to start up, and telling us that
229 // hotspot mode is to be started.
230 mTethering.interfaceStatusChanged(mTestIfname, true);
231 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
232 mLooper.dispatchAll();
233
Erik Kline8351faa2017-04-17 16:47:23 +0900234 verifyInterfaceServingModeStarted();
235 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900236 verify(mNMService, times(1)).setIpForwardingEnabled(true);
237 verify(mNMService, times(1)).startTethering(any(String[].class));
238 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900239 verify(mWifiManager).updateInterfaceIpState(
240 mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
241 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900242 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900243 // UpstreamNetworkMonitor will be started, and will register two callbacks:
244 // a "listen all" and a "track default".
245 verify(mConnectivityManager, times(1)).registerNetworkCallback(
246 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
247 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
248 any(NetworkCallback.class), any(Handler.class));
249 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
250 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
251 verifyNoMoreInteractions(mConnectivityManager);
252
253 // Emulate externally-visible WifiManager effects, when hotspot mode
254 // is being torn down.
255 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
256 mTethering.interfaceRemoved(mTestIfname);
257 mLooper.dispatchAll();
258
259 verify(mNMService, times(1)).untetherInterface(mTestIfname);
260 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
261 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
262 verify(mNMService, atLeastOnce())
263 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
264 verify(mNMService, times(1)).stopTethering();
265 verify(mNMService, times(1)).setIpForwardingEnabled(false);
266 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900267 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900268 // Asking for the last error after the per-interface state machine
269 // has been reaped yields an unknown interface error.
270 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
271 mTethering.getLastTetherError(mTestIfname));
272 }
273
274 @Test
275 public void workingWifiTethering() throws Exception {
276 when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
Erik Klineceb54c62017-04-18 14:22:25 +0900277 when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
Erik Klineea9cc482017-03-10 19:35:34 +0900278
279 // Emulate pressing the WiFi tethering button.
280 mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
281 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900282 verify(mWifiManager, times(1)).startSoftAp(null);
Erik Klineea9cc482017-03-10 19:35:34 +0900283 verifyNoMoreInteractions(mWifiManager);
284 verifyNoMoreInteractions(mConnectivityManager);
285 verifyNoMoreInteractions(mNMService);
286
287 // Emulate externally-visible WifiManager effects, causing the
288 // per-interface state machine to start up, and telling us that
289 // tethering mode is to be started.
290 mTethering.interfaceStatusChanged(mTestIfname, true);
291 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
292 mLooper.dispatchAll();
293
Erik Kline8351faa2017-04-17 16:47:23 +0900294 verifyInterfaceServingModeStarted();
295 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900296 verify(mNMService, times(1)).setIpForwardingEnabled(true);
297 verify(mNMService, times(1)).startTethering(any(String[].class));
298 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900299 verify(mWifiManager).updateInterfaceIpState(
300 mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
301 verifyNoMoreInteractions(mWifiManager);
Erik Kline8351faa2017-04-17 16:47:23 +0900302 verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
Erik Klineea9cc482017-03-10 19:35:34 +0900303 // UpstreamNetworkMonitor will be started, and will register two callbacks:
304 // a "listen all" and a "track default".
305 verify(mConnectivityManager, times(1)).registerNetworkCallback(
306 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
307 verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
308 any(NetworkCallback.class), any(Handler.class));
309 // In tethering mode, in the default configuration, an explicit request
310 // for a mobile network is also made.
311 verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
312 verify(mConnectivityManager, times(1)).requestNetwork(
313 any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
314 any(Handler.class));
315 // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
316 verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
317 verifyNoMoreInteractions(mConnectivityManager);
318
319 /////
320 // We do not currently emulate any upstream being found.
321 //
322 // This is why there are no calls to verify mNMService.enableNat() or
323 // mNMService.startInterfaceForwarding().
324 /////
325
326 // Emulate pressing the WiFi tethering button.
327 mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
328 mLooper.dispatchAll();
Erik Klineceb54c62017-04-18 14:22:25 +0900329 verify(mWifiManager, times(1)).stopSoftAp();
Erik Klineea9cc482017-03-10 19:35:34 +0900330 verifyNoMoreInteractions(mWifiManager);
331 verifyNoMoreInteractions(mConnectivityManager);
332 verifyNoMoreInteractions(mNMService);
333
334 // Emulate externally-visible WifiManager effects, when tethering mode
335 // is being torn down.
336 sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
337 mTethering.interfaceRemoved(mTestIfname);
338 mLooper.dispatchAll();
339
340 verify(mNMService, times(1)).untetherInterface(mTestIfname);
341 // TODO: Why is {g,s}etInterfaceConfig() called more than once?
342 verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
343 verify(mNMService, atLeastOnce())
344 .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
345 verify(mNMService, times(1)).stopTethering();
346 verify(mNMService, times(1)).setIpForwardingEnabled(false);
347 verifyNoMoreInteractions(mNMService);
Erik Kline216af6d2017-04-27 20:57:23 +0900348 verifyNoMoreInteractions(mWifiManager);
Erik Klineea9cc482017-03-10 19:35:34 +0900349 // Asking for the last error after the per-interface state machine
350 // has been reaped yields an unknown interface error.
351 assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
352 mTethering.getLastTetherError(mTestIfname));
353 }
354
355 // TODO: Test that a request for hotspot mode doesn't interface with an
356 // already operating tethering mode interface.
Christopher Wiley497c1472016-10-11 13:26:03 -0700357}