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