WifiServiceImplTest.java revision 0025465e311fe9504cd79610523a1b8171995acc
1/*
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.wifi;
18
19import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
20import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
21import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
22import static android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
23import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
24
25import static com.android.server.wifi.WifiController.CMD_SET_AP;
26import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
27
28import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertFalse;
30import static org.junit.Assert.assertTrue;
31import static org.mockito.Matchers.any;
32import static org.mockito.Matchers.anyString;
33import static org.mockito.Matchers.eq;
34import static org.mockito.Mockito.*;
35
36import android.app.ActivityManager;
37import android.app.AppOpsManager;
38import android.content.ContentResolver;
39import android.content.Context;
40import android.content.res.Resources;
41import android.net.IpConfiguration;
42import android.net.wifi.ScanSettings;
43import android.net.wifi.WifiConfiguration;
44import android.net.wifi.WifiManager;
45import android.os.Handler;
46import android.os.HandlerThread;
47import android.os.IBinder;
48import android.os.IPowerManager;
49import android.os.Looper;
50import android.os.Message;
51import android.os.Messenger;
52import android.os.PowerManager;
53import android.os.UserManager;
54import android.os.WorkSource;
55import android.os.test.TestLooper;
56import android.provider.Settings;
57import android.test.suitebuilder.annotation.SmallTest;
58
59import com.android.internal.util.AsyncChannel;
60import com.android.server.wifi.util.WifiAsyncChannel;
61import com.android.server.wifi.util.WifiPermissionsUtil;
62
63import org.junit.Before;
64import org.junit.Test;
65import org.mockito.Mock;
66import org.mockito.MockitoAnnotations;
67import org.mockito.Spy;
68
69import java.io.FileDescriptor;
70import java.io.PrintWriter;
71import java.io.StringWriter;
72
73/**
74 * Unit tests for {@link WifiServiceImpl}.
75 *
76 * Note: this is intended to build up over time and will not immediately cover the entire file.
77 */
78@SmallTest
79public class WifiServiceImplTest {
80
81    private static final String TAG = "WifiServiceImplTest";
82    private static final String SCAN_PACKAGE_NAME = "scanPackage";
83    private static final String WHITE_LIST_SCAN_PACKAGE_NAME = "whiteListScanPackage";
84    private static final int DEFAULT_VERBOSE_LOGGING = 0;
85    private static final long WIFI_BACKGROUND_SCAN_INTERVAL = 10000;
86    private static final String ANDROID_SYSTEM_PACKAGE = "android";
87    private static final String TEST_PACKAGE_NAME = "TestPackage";
88    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
89    private static final String SYSUI_PACKAGE_NAME = "com.android.systemui";
90
91    private WifiServiceImpl mWifiServiceImpl;
92    private TestLooper mLooper;
93    private PowerManager mPowerManager;
94    private Handler mHandler;
95    private Messenger mAppMessenger;
96
97    @Mock Context mContext;
98    @Mock WifiInjector mWifiInjector;
99    @Mock Clock mClock;
100    @Mock WifiController mWifiController;
101    @Mock WifiTrafficPoller mWifiTrafficPoller;
102    @Mock WifiStateMachine mWifiStateMachine;
103    @Mock HandlerThread mHandlerThread;
104    @Mock AsyncChannel mAsyncChannel;
105    @Mock Resources mResources;
106    @Mock FrameworkFacade mFrameworkFacade;
107    @Mock WifiLockManager mLockManager;
108    @Mock WifiMulticastLockManager mWifiMulticastLockManager;
109    @Mock WifiLastResortWatchdog mWifiLastResortWatchdog;
110    @Mock WifiBackupRestore mWifiBackupRestore;
111    @Mock WifiMetrics mWifiMetrics;
112    @Mock WifiPermissionsUtil mWifiPermissionsUtil;
113    @Mock WifiSettingsStore mSettingsStore;
114    @Mock ContentResolver mContentResolver;
115    @Mock UserManager mUserManager;
116    @Mock WifiConfiguration mApConfig;
117    @Mock ActivityManager mActivityManager;
118    @Mock AppOpsManager mAppOpsManager;
119    @Mock IBinder mAppBinder;
120
121    @Spy FakeWifiLog mLog;
122
123    private class WifiAsyncChannelTester {
124        private static final String TAG = "WifiAsyncChannelTester";
125        public static final int CHANNEL_STATE_FAILURE = -1;
126        public static final int CHANNEL_STATE_DISCONNECTED = 0;
127        public static final int CHANNEL_STATE_HALF_CONNECTED = 1;
128        public static final int CHANNEL_STATE_FULLY_CONNECTED = 2;
129
130        private int mState = CHANNEL_STATE_DISCONNECTED;
131        private WifiAsyncChannel mChannel;
132        private WifiLog mAsyncTestLog;
133
134        WifiAsyncChannelTester(WifiInjector wifiInjector) {
135            mAsyncTestLog = wifiInjector.makeLog(TAG);
136        }
137
138        public int getChannelState() {
139            return mState;
140        }
141
142        public void connect(final Looper looper, final Messenger messenger,
143                final Handler incomingMessageHandler) {
144            assertEquals("AsyncChannel must be in disconnected state",
145                    CHANNEL_STATE_DISCONNECTED, mState);
146            mChannel = new WifiAsyncChannel(TAG);
147            mChannel.setWifiLog(mLog);
148            Handler handler = new Handler(mLooper.getLooper()) {
149                @Override
150                public void handleMessage(Message msg) {
151                    switch (msg.what) {
152                        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
153                            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
154                                mChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
155                                mState = CHANNEL_STATE_HALF_CONNECTED;
156                            } else {
157                                mState = CHANNEL_STATE_FAILURE;
158                            }
159                            break;
160                        case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
161                            mState = CHANNEL_STATE_FULLY_CONNECTED;
162                            break;
163                        case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
164                            mState = CHANNEL_STATE_DISCONNECTED;
165                            break;
166                        default:
167                            incomingMessageHandler.handleMessage(msg);
168                            break;
169                    }
170                }
171            };
172            mChannel.connect(null, handler, messenger);
173        }
174    }
175
176    @Before public void setUp() {
177        MockitoAnnotations.initMocks(this);
178        mLooper = new TestLooper();
179        mHandler = new Handler(mLooper.getLooper());
180        mAppMessenger = new Messenger(mHandler);
181
182        when(mWifiInjector.getUserManager()).thenReturn(mUserManager);
183        when(mWifiInjector.getWifiController()).thenReturn(mWifiController);
184        when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
185        when(mWifiInjector.getWifiStateMachine()).thenReturn(mWifiStateMachine);
186        when(mWifiStateMachine.syncInitialize(any())).thenReturn(true);
187        when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(mHandlerThread);
188        when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
189        when(mContext.getResources()).thenReturn(mResources);
190        when(mContext.getContentResolver()).thenReturn(mContentResolver);
191        doNothing().when(mFrameworkFacade).registerContentObserver(eq(mContext), any(),
192                anyBoolean(), any());
193        when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);
194        when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
195        when(mFrameworkFacade.getLongSetting(
196                eq(mContext),
197                eq(Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS),
198                anyLong()))
199                .thenReturn(WIFI_BACKGROUND_SCAN_INTERVAL);
200        when(mFrameworkFacade.getStringSetting(
201                eq(mContext),
202                eq(Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST)))
203                .thenReturn(WHITE_LIST_SCAN_PACKAGE_NAME);
204        IPowerManager powerManagerService = mock(IPowerManager.class);
205        mPowerManager = new PowerManager(mContext, powerManagerService, new Handler());
206        when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
207        when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
208        WifiAsyncChannel wifiAsyncChannel = new WifiAsyncChannel("WifiServiceImplTest");
209        wifiAsyncChannel.setWifiLog(mLog);
210        when(mFrameworkFacade.makeWifiAsyncChannel(anyString())).thenReturn(wifiAsyncChannel);
211        when(mWifiInjector.getFrameworkFacade()).thenReturn(mFrameworkFacade);
212        when(mWifiInjector.getWifiLockManager()).thenReturn(mLockManager);
213        when(mWifiInjector.getWifiMulticastLockManager()).thenReturn(mWifiMulticastLockManager);
214        when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog);
215        when(mWifiInjector.getWifiBackupRestore()).thenReturn(mWifiBackupRestore);
216        when(mWifiInjector.makeLog(anyString())).thenReturn(mLog);
217        WifiTrafficPoller wifiTrafficPoller = new WifiTrafficPoller(mContext,
218                mLooper.getLooper(), "mockWlan");
219        when(mWifiInjector.getWifiTrafficPoller()).thenReturn(wifiTrafficPoller);
220        when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
221        when(mWifiInjector.getWifiSettingsStore()).thenReturn(mSettingsStore);
222        when(mWifiInjector.getClock()).thenReturn(mClock);
223        mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel);
224        mWifiServiceImpl.setWifiHandlerLogForTest(mLog);
225    }
226
227    @Test
228    public void testRemoveNetworkUnknown() {
229        assertFalse(mWifiServiceImpl.removeNetwork(-1));
230    }
231
232    @Test
233    public void testAsyncChannelHalfConnected() {
234        WifiAsyncChannelTester channelTester = new WifiAsyncChannelTester(mWifiInjector);
235        Handler handler = mock(Handler.class);
236        TestLooper looper = new TestLooper();
237        channelTester.connect(looper.getLooper(), mWifiServiceImpl.getWifiServiceMessenger(),
238                handler);
239        mLooper.dispatchAll();
240        assertEquals("AsyncChannel must be half connected",
241                WifiAsyncChannelTester.CHANNEL_STATE_HALF_CONNECTED,
242                channelTester.getChannelState());
243    }
244
245    /**
246     * Tests the isValid() check for StaticIpConfigurations, ensuring that configurations with null
247     * ipAddress are rejected, and configurations with ipAddresses are valid.
248     */
249    @Test
250    public void testStaticIpConfigurationValidityCheck() {
251        WifiConfiguration conf = WifiConfigurationTestUtil.createOpenNetwork();
252        IpConfiguration ipConf =
253                WifiConfigurationTestUtil.createStaticIpConfigurationWithStaticProxy();
254        conf.setIpConfiguration(ipConf);
255        // Ensure staticIpConfiguration with IP Address is valid
256        assertTrue(mWifiServiceImpl.isValid(conf));
257        ipConf.staticIpConfiguration.ipAddress = null;
258        // Ensure staticIpConfiguration with null IP Address it is not valid
259        conf.setIpConfiguration(ipConf);
260        assertFalse(mWifiServiceImpl.isValid(conf));
261    }
262
263    /**
264     * Ensure WifiMetrics.dump() is the only dump called when 'dumpsys wifi WifiMetricsProto' is
265     * called. This is required to support simple metrics collection via dumpsys
266     */
267    @Test
268    public void testWifiMetricsDump() {
269        mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()),
270                new String[]{mWifiMetrics.PROTO_DUMP_ARG});
271        verify(mWifiMetrics)
272                .dump(any(FileDescriptor.class), any(PrintWriter.class), any(String[].class));
273        verify(mWifiStateMachine, never())
274                .dump(any(FileDescriptor.class), any(PrintWriter.class), any(String[].class));
275    }
276
277
278    /**
279     * Verify that wifi can be enabled by a caller with WIFI_STATE_CHANGE permission when wifi is
280     * off (no hotspot, no airplane mode).
281     */
282    @Test
283    public void testSetWifiEnabledSuccess() throws Exception {
284        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
285        when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
286        assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
287        verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
288    }
289
290    /**
291     * Verify that the CMD_TOGGLE_WIFI message won't be sent if wifi is already on.
292     */
293    @Test
294    public void testSetWifiEnabledNoToggle() throws Exception {
295        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
296        when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(false);
297        assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
298        verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
299    }
300
301    /**
302     * Verify a SecurityException is thrown if a caller does not have the correct permission to
303     * toggle wifi.
304     */
305    @Test(expected = SecurityException.class)
306    public void testSetWifiEnableWithoutPermission() throws Exception {
307        doThrow(new SecurityException()).when(mContext)
308                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
309                                                eq("WifiService"));
310        mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true);
311        verify(mWifiStateMachine, never()).syncGetWifiApState();
312    }
313
314    /**
315     * Verify that a call from Settings can enable wifi if we are in softap mode.
316     */
317    @Test
318    public void testSetWifiEnabledFromSettingsWhenApEnabled() throws Exception {
319        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
320        when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
321        assertTrue(mWifiServiceImpl.setWifiEnabled(SETTINGS_PACKAGE_NAME, true));
322        verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
323    }
324
325    /**
326     * Verify that a call from SysUI can enable wifi if we are in softap mode.
327     */
328    @Test
329    public void testSetWifiEnabledFromSysUiWhenApEnabled() throws Exception {
330        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
331        when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
332        assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true));
333        verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
334    }
335
336    /**
337     * Verify that a call from an app cannot enable wifi if we are in softap mode.
338     */
339    @Test
340    public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception {
341        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
342        assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
343        verify(mSettingsStore, never()).handleWifiToggled(anyBoolean());
344        verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
345    }
346
347    /**
348     * Verify that wifi can be disabled by a caller with WIFI_STATE_CHANGE permission when wifi is
349     * on.
350     */
351    @Test
352    public void testSetWifiDisabledSuccess() throws Exception {
353        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
354        when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true);
355        assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
356        verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
357    }
358
359    /**
360     * Verify that CMD_TOGGLE_WIFI message won't be sent if wifi is already off.
361     */
362    @Test
363    public void testSetWifiDisabledNoToggle() throws Exception {
364        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
365        when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(false);
366        assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
367        verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
368    }
369
370    /**
371     * Verify a SecurityException is thrown if a caller does not have the correct permission to
372     * toggle wifi.
373     */
374    @Test(expected = SecurityException.class)
375    public void testSetWifiDisabledWithoutPermission() throws Exception {
376        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
377        doThrow(new SecurityException()).when(mContext)
378                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
379                                                eq("WifiService"));
380        mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false);
381    }
382
383    /**
384     * Ensure unpermitted callers cannot write the SoftApConfiguration.
385     *
386     * @throws SecurityException
387     */
388    @Test(expected = SecurityException.class)
389    public void testSetWifiApConfigurationNotSavedWithoutPermission() {
390        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(false);
391        WifiConfiguration apConfig = new WifiConfiguration();
392        mWifiServiceImpl.setWifiApConfiguration(apConfig);
393        verify(mWifiStateMachine, never()).setWifiApConfiguration(eq(apConfig));
394    }
395
396    /**
397     * Ensure softap config is written when the caller has the correct permission.
398     */
399    @Test
400    public void testSetWifiApConfigurationSuccess() {
401        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
402        WifiConfiguration apConfig = new WifiConfiguration();
403        mWifiServiceImpl.setWifiApConfiguration(apConfig);
404        verify(mWifiStateMachine).setWifiApConfiguration(eq(apConfig));
405    }
406
407    /**
408     * Ensure that a null config does not overwrite the saved ap config.
409     */
410    @Test
411    public void testSetWifiApConfigurationNullConfigNotSaved() {
412        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
413        mWifiServiceImpl.setWifiApConfiguration(null);
414        verify(mWifiStateMachine, never()).setWifiApConfiguration(isNull(WifiConfiguration.class));
415    }
416
417    /**
418     * Ensure unpermitted callers are not able to retrieve the softap config.
419     *
420     * @throws SecurityException
421     */
422    @Test(expected = SecurityException.class)
423    public void testGetWifiApConfigurationNotReturnedWithoutPermission() {
424        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(false);
425        mWifiServiceImpl.getWifiApConfiguration();
426        verify(mWifiStateMachine, never()).syncGetWifiApConfiguration();
427    }
428
429    /**
430     * Ensure permitted callers are able to retrieve the softap config.
431     */
432    @Test
433    public void testGetWifiApConfigurationSuccess() {
434        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
435        WifiConfiguration apConfig = new WifiConfiguration();
436        when(mWifiStateMachine.syncGetWifiApConfiguration()).thenReturn(apConfig);
437        assertEquals(apConfig, mWifiServiceImpl.getWifiApConfiguration());
438    }
439
440    /**
441     * Make sure we do not start wifi if System services have to be restarted to decrypt the device.
442     */
443    @Test
444    public void testWifiControllerDoesNotStartWhenDeviceTriggerResetMainAtBoot() {
445        when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(true);
446        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
447        mWifiServiceImpl.checkAndStartWifi();
448        verify(mWifiController, never()).start();
449    }
450
451    /**
452     * Make sure we do start WifiController (wifi disabled) if the device is already decrypted.
453     */
454    @Test
455    public void testWifiControllerStartsWhenDeviceIsDecryptedAtBootWithWifiDisabled() {
456        when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
457        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
458        mWifiServiceImpl.checkAndStartWifi();
459        verify(mWifiController).start();
460        verify(mWifiController, never()).sendMessage(CMD_WIFI_TOGGLED);
461    }
462
463    /**
464     * Make sure we do start WifiController (wifi enabled) if the device is already decrypted.
465     */
466    @Test
467    public void testWifiFullyStartsWhenDeviceIsDecryptedAtBootWithWifiEnabled() {
468        when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
469        when(mSettingsStore.handleWifiToggled(true)).thenReturn(true);
470        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
471        when(mWifiStateMachine.syncGetWifiState()).thenReturn(WIFI_STATE_DISABLED);
472        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
473        when(mContext.getPackageName()).thenReturn(ANDROID_SYSTEM_PACKAGE);
474        mWifiServiceImpl.checkAndStartWifi();
475        verify(mWifiController).start();
476        verify(mWifiController).sendMessage(CMD_WIFI_TOGGLED);
477    }
478
479    /**
480     * Verify setWifiApEnabled works with the correct permissions and a null config.
481     */
482    @Test
483    public void testSetWifiApEnabledWithProperPermissionsWithNullConfig() {
484        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
485        when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
486                .thenReturn(false);
487        mWifiServiceImpl.setWifiApEnabled(null, true);
488        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(1), eq(0), eq(null));
489    }
490
491    /**
492     * Verify setWifiApEnabled works with correct permissions and a valid config.
493     *
494     * TODO: should really validate that ap configs have a set of basic config settings b/37280779
495     */
496    @Test
497    public void testSetWifiApEnabledWithProperPermissionsWithValidConfig() {
498        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
499        when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
500                .thenReturn(false);
501        WifiConfiguration apConfig = new WifiConfiguration();
502        mWifiServiceImpl.setWifiApEnabled(apConfig, true);
503        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(1), eq(0), eq(apConfig));
504    }
505
506    /**
507     * Verify setWifiApEnabled when disabling softap with correct permissions sends the correct
508     * message to WifiController.
509     */
510    @Test
511    public void testSetWifiApEnabledFalseWithProperPermissionsWithNullConfig() {
512        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
513        when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
514                .thenReturn(false);
515        mWifiServiceImpl.setWifiApEnabled(null, false);
516        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), eq(0), eq(null));
517    }
518
519    /**
520     * setWifiApEnabled should fail if the provided config is not valid.
521     */
522    @Test
523    public void testSetWifiApEnabledWithProperPermissionInvalidConfigFails() {
524        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
525        when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
526                .thenReturn(false);
527        // mApConfig is a mock and the values are not set - triggering the invalid config.  Testing
528        // will be improved when we actually do test softap configs in b/37280779
529        mWifiServiceImpl.setWifiApEnabled(mApConfig, true);
530        verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(1), eq(0), eq(mApConfig));
531    }
532
533    /**
534     * setWifiApEnabled should throw a security exception when the caller does not have the correct
535     * permissions.
536     */
537    @Test(expected = SecurityException.class)
538    public void testSetWifiApEnabledThrowsSecurityExceptionWithoutConfigOverridePermission()
539            throws Exception {
540        doThrow(new SecurityException()).when(mContext)
541                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
542                        eq("WifiService"));
543        mWifiServiceImpl.setWifiApEnabled(null, true);
544    }
545
546    /**
547     * setWifiApEnabled should throw a SecurityException when disallow tethering is set for the
548     * user.
549     */
550    @Test(expected = SecurityException.class)
551    public void testSetWifiApEnabledThrowsSecurityExceptionWithDisallowTethering()
552            throws Exception {
553        when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
554        when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
555                .thenReturn(true);
556        mWifiServiceImpl.setWifiApEnabled(null, true);
557
558    }
559
560    /**
561     * Verify caller with proper permission can call startSoftAp.
562     */
563    @Test
564    public void testStartSoftApWithPermissionsAndNullConfig() {
565        boolean result = mWifiServiceImpl.startSoftAp(null);
566        assertTrue(result);
567        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(1), eq(0), eq(null));
568    }
569
570    /**
571     * Verify caller with proper permissions but an invalid config does not start softap.
572     */
573    @Test
574    public void testStartSoftApWithPermissionsAndInvalidConfig() {
575        boolean result = mWifiServiceImpl.startSoftAp(mApConfig);
576        assertFalse(result);
577        verifyZeroInteractions(mWifiController);
578    }
579
580    /**
581     * Verify caller with proper permission and valid config does start softap.
582     */
583    @Test
584    public void testStartSoftApWithPermissionsAndValidConfig() {
585        WifiConfiguration config = new WifiConfiguration();
586        boolean result = mWifiServiceImpl.startSoftAp(config);
587        assertTrue(result);
588        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(1), eq(0), eq(config));
589    }
590
591    /**
592     * Verify a SecurityException is thrown when a caller without the correct permission attempts to
593     * start softap.
594     */
595    @Test(expected = SecurityException.class)
596    public void testStartSoftApWithoutPermissionThrowsException() throws Exception {
597        doThrow(new SecurityException()).when(mContext)
598                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_STACK),
599                                                eq("WifiService"));
600        mWifiServiceImpl.startSoftAp(null);
601    }
602
603    /**
604     * Verify caller with proper permission can call stopSoftAp.
605     */
606    @Test
607    public void testStopSoftApWithPermissions() {
608        boolean result = mWifiServiceImpl.stopSoftAp();
609        assertTrue(result);
610        verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), eq(0));
611    }
612
613    /**
614     * Verify SecurityException is thrown when a caller without the correct permission attempts to
615     * stop softap.
616     */
617    @Test(expected = SecurityException.class)
618    public void testStopSoftApWithoutPermissionThrowsException() throws Exception {
619        doThrow(new SecurityException()).when(mContext)
620                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_STACK),
621                                                eq("WifiService"));
622        mWifiServiceImpl.stopSoftAp();
623    }
624
625    /**
626     * Ensure foreground apps can always do wifi scans.
627     */
628    @Test
629    public void testWifiScanStartedForeground() {
630        when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
631                ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
632        mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
633        verify(mWifiStateMachine).startScan(
634                anyInt(), anyInt(), (ScanSettings) eq(null), any(WorkSource.class));
635    }
636
637    /**
638     * Ensure background apps get throttled when the previous scan is too close.
639     */
640    @Test
641    public void testWifiScanBackgroundThrottled() {
642        when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
643                ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
644        long startMs = 1000;
645        when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
646        mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
647        verify(mWifiStateMachine).startScan(
648                anyInt(), anyInt(), (ScanSettings) eq(null), any(WorkSource.class));
649
650        when(mClock.getElapsedSinceBootMillis()).thenReturn(
651                startMs + WIFI_BACKGROUND_SCAN_INTERVAL - 1000);
652        mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
653        verify(mWifiStateMachine, times(1)).startScan(
654                anyInt(), anyInt(), (ScanSettings) eq(null), any(WorkSource.class));
655    }
656
657    /**
658     * Ensure background apps can do wifi scan when the throttle interval reached.
659     */
660    @Test
661    public void testWifiScanBackgroundNotThrottled() {
662        when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
663                ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
664        long startMs = 1000;
665        when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
666        mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
667        verify(mWifiStateMachine).startScan(
668                anyInt(), eq(0), (ScanSettings) eq(null), any(WorkSource.class));
669
670        when(mClock.getElapsedSinceBootMillis()).thenReturn(
671                startMs + WIFI_BACKGROUND_SCAN_INTERVAL + 1000);
672        mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
673        verify(mWifiStateMachine).startScan(
674                anyInt(), eq(1), (ScanSettings) eq(null), any(WorkSource.class));
675    }
676
677    /**
678     * Ensure background apps can do wifi scan when the throttle interval reached.
679     */
680    @Test
681    public void testWifiScanBackgroundWhiteListed() {
682        when(mActivityManager.getPackageImportance(WHITE_LIST_SCAN_PACKAGE_NAME)).thenReturn(
683                ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
684        long startMs = 1000;
685        when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
686        mWifiServiceImpl.startScan(null, null, WHITE_LIST_SCAN_PACKAGE_NAME);
687        verify(mWifiStateMachine).startScan(
688                anyInt(), anyInt(), (ScanSettings) eq(null), any(WorkSource.class));
689
690        when(mClock.getElapsedSinceBootMillis()).thenReturn(
691                startMs + WIFI_BACKGROUND_SCAN_INTERVAL - 1000);
692        mWifiServiceImpl.startScan(null, null, WHITE_LIST_SCAN_PACKAGE_NAME);
693        verify(mWifiStateMachine, times(2)).startScan(
694                anyInt(), anyInt(), (ScanSettings) eq(null), any(WorkSource.class));
695    }
696
697    /**
698     * Verify that the call to startLocalOnlyHotspot throws the UnsupportedOperationException
699     * until the implementation is complete.
700     */
701    @Test(expected = UnsupportedOperationException.class)
702    public void testStartLocalOnlyHotspotNotSupported() {
703        // allow test to proceed without a permission check failure
704        when(mSettingsStore.getLocationModeSetting(mContext))
705                .thenReturn(LOCATION_MODE_HIGH_ACCURACY);
706        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING))
707                .thenReturn(false);
708        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
709        mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
710    }
711
712    /**
713     * Verify that a call to startLocalOnlyHotspot throws a SecurityException if the caller does not
714     * have the CHANGE_WIFI_STATE permission.
715     */
716    @Test(expected = SecurityException.class)
717    public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutCorrectPermission() {
718        doThrow(new SecurityException()).when(mContext)
719                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
720                                                eq("WifiService"));
721        mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
722    }
723
724    /**
725     * Verify that a call to startLocalOnlyHotspot throws a SecurityException if the caller does not
726     * have Location permission.
727     */
728    @Test(expected = SecurityException.class)
729    public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutLocationPermission() {
730        when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME);
731        doThrow(new SecurityException())
732                .when(mWifiPermissionsUtil).enforceLocationPermission(eq(TEST_PACKAGE_NAME),
733                                                                      anyInt());
734        mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
735    }
736
737    /**
738     * Verify that a call to startLocalOnlyHotspot throws a SecurityException if Location mode is
739     * disabled.
740     */
741    @Test(expected = SecurityException.class)
742    public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutLocationEnabled() {
743        when(mSettingsStore.getLocationModeSetting(mContext)).thenReturn(LOCATION_MODE_OFF);
744        mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
745    }
746
747    /**
748     * Only start LocalOnlyHotspot if we are not tethering.
749     */
750    @Test
751    public void testHotspotDoesNotStartWhenAlreadyTethering() {
752        when(mSettingsStore.getLocationModeSetting(mContext))
753                            .thenReturn(LOCATION_MODE_HIGH_ACCURACY);
754        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
755        int returnCode = mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
756        assertEquals(ERROR_INCOMPATIBLE_MODE, returnCode);
757    }
758
759    /**
760     * Only start LocalOnlyHotspot if admin setting does not disallow tethering.
761     */
762    @Test
763    public void testHotspotDoesNotStartWhenTetheringDisallowed() {
764        when(mSettingsStore.getLocationModeSetting(mContext))
765                .thenReturn(LOCATION_MODE_HIGH_ACCURACY);
766        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING))
767                .thenReturn(true);
768        when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
769        int returnCode = mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder);
770        assertEquals(ERROR_TETHERING_DISALLOWED, returnCode);
771    }
772
773    /**
774     * Verify that the call to stopLocalOnlyHotspot throws the UnsupportedOperationException until
775     * the implementation is complete.
776     */
777    @Test(expected = UnsupportedOperationException.class)
778    public void testStopLocalOnlyHotspotNotSupported() {
779        // allow test to proceed without a permission check failure
780        mWifiServiceImpl.stopLocalOnlyHotspot();
781    }
782
783    /**
784     * Verify that a call to stopLocalOnlyHotspot throws a SecurityException if the caller does not
785     * have the CHANGE_WIFI_STATE permission.
786     */
787    @Test(expected = SecurityException.class)
788    public void testStopLocalOnlyHotspotThrowsSecurityExceptionWithoutCorrectPermission() {
789        doThrow(new SecurityException()).when(mContext)
790                .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
791                                                eq("WifiService"));
792        mWifiServiceImpl.stopLocalOnlyHotspot();
793    }
794
795    /**
796     * Verify that the call to startWatchLocalOnlyHotspot throws the UnsupportedOperationException
797     * until the implementation is complete.
798     */
799    @Test(expected = UnsupportedOperationException.class)
800    public void testStartWatchLocalOnlyHotspotNotSupported() {
801        mWifiServiceImpl.startWatchLocalOnlyHotspot(mAppMessenger, mAppBinder);
802    }
803
804    /**
805     * Verify that the call to stopWatchLocalOnlyHotspot throws the UnsupportedOperationException
806     * until the implementation is complete.
807     */
808    @Test(expected = UnsupportedOperationException.class)
809    public void testStopWatchLocalOnlyHotspotNotSupported() {
810        mWifiServiceImpl.stopWatchLocalOnlyHotspot();
811    }
812}
813