WifiStateMachineTest.java revision d0846fa841b604ccb969c54b45367fa2bececf83
1/*
2 * Copyright (C) 2015 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 org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertTrue;
22import static org.mockito.Mockito.any;
23import static org.mockito.Mockito.anyBoolean;
24import static org.mockito.Mockito.anyInt;
25import static org.mockito.Mockito.anyObject;
26import static org.mockito.Mockito.anyString;
27import static org.mockito.Mockito.eq;
28import static org.mockito.Mockito.mock;
29import static org.mockito.Mockito.never;
30import static org.mockito.Mockito.verify;
31import static org.mockito.Mockito.when;
32import static org.mockito.Mockito.withSettings;
33
34import android.content.ContentResolver;
35import android.content.Context;
36import android.content.pm.PackageManager;
37import android.content.pm.UserInfo;
38import android.content.res.Resources;
39import android.net.ConnectivityManager;
40import android.net.DhcpResults;
41import android.net.LinkProperties;
42import android.net.dhcp.DhcpClient;
43import android.net.ip.IpManager;
44import android.net.wifi.ScanResult;
45import android.net.wifi.SupplicantState;
46import android.net.wifi.WifiConfiguration;
47import android.net.wifi.WifiManager;
48import android.net.wifi.WifiSsid;
49import android.net.wifi.p2p.IWifiP2pManager;
50import android.os.BatteryStats;
51import android.os.Binder;
52import android.os.Handler;
53import android.os.HandlerThread;
54import android.os.IBinder;
55import android.os.IInterface;
56import android.os.INetworkManagementService;
57import android.os.IPowerManager;
58import android.os.Looper;
59import android.os.Message;
60import android.os.Messenger;
61import android.os.PowerManager;
62import android.os.UserHandle;
63import android.os.UserManager;
64import android.provider.Settings;
65import android.test.suitebuilder.annotation.SmallTest;
66import android.util.Log;
67
68import com.android.internal.R;
69import com.android.internal.app.IBatteryStats;
70import com.android.internal.util.AsyncChannel;
71import com.android.internal.util.IState;
72import com.android.internal.util.StateMachine;
73import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
74import com.android.server.wifi.hotspot2.NetworkDetail;
75import com.android.server.wifi.hotspot2.Utils;
76import com.android.server.wifi.p2p.WifiP2pServiceImpl;
77
78import org.junit.After;
79import org.junit.Before;
80import org.junit.Test;
81import org.mockito.Mock;
82import org.mockito.Mockito;
83import org.mockito.MockitoAnnotations;
84
85import java.io.ByteArrayOutputStream;
86import java.io.PrintWriter;
87import java.lang.reflect.Field;
88import java.lang.reflect.InvocationTargetException;
89import java.lang.reflect.Method;
90import java.util.ArrayList;
91import java.util.Arrays;
92import java.util.HashMap;
93import java.util.List;
94import java.util.Map;
95
96/**
97 * Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
98 */
99@SmallTest
100public class WifiStateMachineTest {
101    public static final String TAG = "WifiStateMachineTest";
102
103    private static final int MANAGED_PROFILE_UID = 1100000;
104    private static final int OTHER_USER_UID = 1200000;
105
106    private long mBinderToken;
107
108    private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) {
109        return mock(class1, withSettings().extraInterfaces(interfaces));
110    }
111
112    private static <T, I> IBinder mockService(Class<T> class1, Class<I> iface) {
113        T tImpl = mockWithInterfaces(class1, iface);
114        IBinder binder = mock(IBinder.class);
115        when(((IInterface) tImpl).asBinder()).thenReturn(binder);
116        when(binder.queryLocalInterface(iface.getCanonicalName()))
117                .thenReturn((IInterface) tImpl);
118        return binder;
119    }
120
121    private void enableDebugLogs() {
122        mWsm.enableVerboseLogging(1);
123    }
124
125    private class TestIpManager extends IpManager {
126        TestIpManager(Context context, String ifname, IpManager.Callback callback) {
127            // Call test-only superclass constructor.
128            super(ifname, callback);
129        }
130
131        @Override
132        public void startProvisioning(IpManager.ProvisioningConfiguration config) {}
133
134        @Override
135        public void stop() {}
136
137        @Override
138        public void confirmConfiguration() {}
139
140        void injectDhcpSuccess(DhcpResults dhcpResults) {
141            mCallback.onNewDhcpResults(dhcpResults);
142            mCallback.onProvisioningSuccess(new LinkProperties());
143        }
144
145        void injectDhcpFailure() {
146            mCallback.onNewDhcpResults(null);
147            mCallback.onProvisioningFailure(new LinkProperties());
148        }
149    }
150
151    private FrameworkFacade getFrameworkFacade() throws Exception {
152        FrameworkFacade facade = mock(FrameworkFacade.class);
153
154        when(facade.makeBaseLogger()).thenReturn(mock(BaseWifiLogger.class));
155        when(facade.getService(Context.NETWORKMANAGEMENT_SERVICE)).thenReturn(
156                mockWithInterfaces(IBinder.class, INetworkManagementService.class));
157
158        IBinder p2pBinder = mockService(WifiP2pServiceImpl.class, IWifiP2pManager.class);
159        when(facade.getService(Context.WIFI_P2P_SERVICE)).thenReturn(p2pBinder);
160
161        WifiP2pServiceImpl p2pm = (WifiP2pServiceImpl) p2pBinder.queryLocalInterface(
162                IWifiP2pManager.class.getCanonicalName());
163
164        final Object sync = new Object();
165        synchronized (sync) {
166            mP2pThread = new HandlerThread("WifiP2pMockThread") {
167                @Override
168                protected void onLooperPrepared() {
169                    synchronized (sync) {
170                        sync.notifyAll();
171                    }
172                }
173            };
174
175            mP2pThread.start();
176            sync.wait();
177        }
178
179        Handler handler = new Handler(mP2pThread.getLooper());
180        when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler));
181
182        IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
183        when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
184
185        when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class)))
186                .then(new AnswerWithArguments() {
187                    public IpManager answer(
188                            Context context, String ifname, IpManager.Callback callback) {
189                        mTestIpManager = new TestIpManager(context, ifname, callback);
190                        return mTestIpManager;
191                    }
192                });
193
194        when(facade.checkUidPermission(eq(android.Manifest.permission.OVERRIDE_WIFI_CONFIG),
195                anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
196
197        return facade;
198    }
199
200    private Context getContext() throws Exception {
201        PackageManager pkgMgr = mock(PackageManager.class);
202        when(pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
203
204        Context context = mock(Context.class);
205        when(context.getPackageManager()).thenReturn(pkgMgr);
206        when(context.getContentResolver()).thenReturn(mock(ContentResolver.class));
207
208        MockResources resources = new com.android.server.wifi.MockResources();
209        when(context.getResources()).thenReturn(resources);
210
211        ContentResolver cr = mock(ContentResolver.class);
212        when(context.getContentResolver()).thenReturn(cr);
213
214        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(
215                new PowerManager(context, mock(IPowerManager.class), new Handler()));
216
217        mAlarmManager = new MockAlarmManager();
218        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
219                mAlarmManager.getAlarmManager());
220
221        when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
222                mock(ConnectivityManager.class));
223
224        return context;
225    }
226
227    private Resources getMockResources() {
228        MockResources resources = new MockResources();
229        resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false);
230        return resources;
231    }
232
233    private IState getCurrentState() throws
234            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
235        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
236        method.setAccessible(true);
237        return (IState) method.invoke(mWsm);
238    }
239
240    private static HandlerThread getWsmHandlerThread(WifiStateMachine wsm) throws
241            NoSuchFieldException, InvocationTargetException, IllegalAccessException {
242        Field field = StateMachine.class.getDeclaredField("mSmThread");
243        field.setAccessible(true);
244        return (HandlerThread) field.get(wsm);
245    }
246
247    private static void stopLooper(final Looper looper) throws Exception {
248        new Handler(looper).post(new Runnable() {
249            @Override
250            public void run() {
251                looper.quitSafely();
252            }
253        });
254    }
255
256    private void dumpState() {
257        ByteArrayOutputStream stream = new ByteArrayOutputStream();
258        PrintWriter writer = new PrintWriter(stream);
259        mWsm.dump(null, writer, null);
260        writer.flush();
261        Log.d(TAG, "WifiStateMachine state -" + stream.toString());
262    }
263
264    private static ScanDetail getGoogleGuestScanDetail(int rssi) {
265        ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
266        ie[0] = ScanResults.generateSsidIe(sSSID);
267        NetworkDetail nd = new NetworkDetail(sBSSID, ie, new ArrayList<String>(), sFreq);
268        ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq,
269                Long.MAX_VALUE, /* needed so that scan results aren't rejected because
270                                   there older than scan start */
271                null, null);
272        return detail;
273    }
274
275    private ArrayList<ScanDetail> getMockScanResults() {
276        ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
277        ArrayList<ScanDetail> list = sr.getScanDetailArrayList();
278
279        int rssi = -65;
280        list.add(getGoogleGuestScanDetail(rssi));
281        return list;
282    }
283
284    static final String   sSSID = "\"GoogleGuest\"";
285    static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
286    static final String   sHexSSID = sWifiSsid.getHexString().replace("0x", "").replace("22", "");
287    static final String   sBSSID = "01:02:03:04:05:06";
288    static final int      sFreq = 2437;
289
290    WifiStateMachine mWsm;
291    HandlerThread mWsmThread;
292    HandlerThread mP2pThread;
293    HandlerThread mSyncThread;
294    AsyncChannel  mWsmAsyncChannel;
295    MockAlarmManager mAlarmManager;
296    MockWifiMonitor mWifiMonitor;
297    TestIpManager mTestIpManager;
298    MockLooper mLooper;
299
300    @Mock WifiNative mWifiNative;
301    @Mock SupplicantStateTracker mSupplicantStateTracker;
302    @Mock WifiMetrics mWifiMetrics;
303    @Mock UserManager mUserManager;
304
305    public WifiStateMachineTest() throws Exception {
306    }
307
308    @Before
309    public void setUp() throws Exception {
310        Log.d(TAG, "Setting up ...");
311
312        // Ensure looper exists
313        mLooper = new MockLooper();
314
315        MockitoAnnotations.initMocks(this);
316
317        /** uncomment this to enable logs from WifiStateMachines */
318        // enableDebugLogs();
319
320        TestUtil.installWlanWifiNative(mWifiNative);
321        mWifiMonitor = new MockWifiMonitor();
322        mWifiMetrics = mock(WifiMetrics.class);
323        FrameworkFacade factory = getFrameworkFacade();
324        Context context = getContext();
325
326        Resources resources = getMockResources();
327        when(context.getResources()).thenReturn(resources);
328
329        when(factory.getIntegerSetting(context,
330                Settings.Global.WIFI_FREQUENCY_BAND,
331                WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn(
332                WifiManager.WIFI_FREQUENCY_BAND_AUTO);
333
334        when(factory.makeApConfigStore(Mockito.eq(context)))
335                .thenCallRealMethod();
336
337        when(factory.makeSupplicantStateTracker(
338                any(Context.class), any(WifiStateMachine.class), any(WifiConfigStore.class),
339                any(Handler.class))).thenReturn(mSupplicantStateTracker);
340
341        when(mUserManager.getProfileParent(11))
342                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0));
343        when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList(
344                new UserInfo(UserHandle.USER_SYSTEM, "owner", 0),
345                new UserInfo(11, "managed profile", 0)));
346
347        mWsm = new WifiStateMachine(context, factory, mLooper.getLooper(),
348            mUserManager, mWifiMetrics);
349        mWsmThread = getWsmHandlerThread(mWsm);
350
351        final AsyncChannel channel = new AsyncChannel();
352        Handler handler = new Handler(mLooper.getLooper()) {
353            @Override
354            public void handleMessage(Message msg) {
355                switch (msg.what) {
356                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
357                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
358                            mWsmAsyncChannel = channel;
359                        } else {
360                            Log.d(TAG, "Failed to connect Command channel " + this);
361                        }
362                        break;
363                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
364                        Log.d(TAG, "Command channel disconnected" + this);
365                        break;
366                }
367            }
368        };
369
370        channel.connect(context, handler, mWsm.getMessenger());
371        mLooper.dispatchAll();
372        /* Now channel is supposed to be connected */
373
374        mBinderToken = Binder.clearCallingIdentity();
375    }
376
377    @After
378    public void cleanUp() throws Exception {
379        Binder.restoreCallingIdentity(mBinderToken);
380
381        if (mSyncThread != null) stopLooper(mSyncThread.getLooper());
382        if (mWsmThread != null) stopLooper(mWsmThread.getLooper());
383        if (mP2pThread != null) stopLooper(mP2pThread.getLooper());
384
385        mWsmThread = null;
386        mP2pThread = null;
387        mSyncThread = null;
388        mWsmAsyncChannel = null;
389        mWsm = null;
390    }
391
392    @Test
393    public void createNew() throws Exception {
394        assertEquals("InitialState", getCurrentState().getName());
395
396        mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
397        mLooper.dispatchAll();
398        assertEquals("InitialState", getCurrentState().getName());
399    }
400
401    @Test
402    public void loadComponents() throws Exception {
403        when(mWifiNative.loadDriver()).thenReturn(true);
404        when(mWifiNative.startHal()).thenReturn(true);
405        when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(true);
406        mWsm.setSupplicantRunning(true);
407        mLooper.dispatchAll();
408
409        assertEquals("SupplicantStartingState", getCurrentState().getName());
410
411        when(mWifiNative.setBand(anyInt())).thenReturn(true);
412        when(mWifiNative.setDeviceName(anyString())).thenReturn(true);
413        when(mWifiNative.setManufacturer(anyString())).thenReturn(true);
414        when(mWifiNative.setModelName(anyString())).thenReturn(true);
415        when(mWifiNative.setModelNumber(anyString())).thenReturn(true);
416        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
417        when(mWifiNative.setConfigMethods(anyString())).thenReturn(true);
418        when(mWifiNative.setDeviceType(anyString())).thenReturn(true);
419        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
420        when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true);
421        when(mWifiNative.enableBackgroundScan(anyBoolean(),
422                any(ArrayList.class))).thenReturn(true);
423
424        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
425        mLooper.dispatchAll();
426
427        assertEquals("DisconnectedState", getCurrentState().getName());
428    }
429
430    @Test
431    public void loadComponentsFailure() throws Exception {
432        when(mWifiNative.loadDriver()).thenReturn(false);
433        when(mWifiNative.startHal()).thenReturn(false);
434        when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(false);
435
436        mWsm.setSupplicantRunning(true);
437        mLooper.dispatchAll();
438        assertEquals("InitialState", getCurrentState().getName());
439
440        when(mWifiNative.loadDriver()).thenReturn(true);
441        mWsm.setSupplicantRunning(true);
442        mLooper.dispatchAll();
443        assertEquals("InitialState", getCurrentState().getName());
444
445        when(mWifiNative.startHal()).thenReturn(true);
446        mWsm.setSupplicantRunning(true);
447        mLooper.dispatchAll();
448        assertEquals("InitialState", getCurrentState().getName());
449    }
450
451    private void addNetworkAndVerifySuccess() throws Exception {
452        loadComponents();
453
454        final HashMap<String, String> nameToValue = new HashMap<String, String>();
455
456        when(mWifiNative.addNetwork()).thenReturn(0);
457        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString()))
458                .then(new AnswerWithArguments() {
459                    public boolean answer(int netId, String name, String value) {
460                        if (netId != 0) {
461                            Log.d(TAG, "Can't set var " + name + " for " + netId);
462                            return false;
463                        }
464
465                        Log.d(TAG, "Setting var " + name + " to " + value + " for " + netId);
466                        nameToValue.put(name, value);
467                        return true;
468                    }
469                });
470
471        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
472                .then(new AnswerWithArguments() {
473                    public boolean answer(int netId, String name, Map<String, String> values) {
474                        if (netId != 0) {
475                            Log.d(TAG, "Can't set extra " + name + " for " + netId);
476                            return false;
477                        }
478
479                        Log.d(TAG, "Setting extra for " + netId);
480                        return true;
481                    }
482                });
483
484        when(mWifiNative.getNetworkVariable(anyInt(), anyString()))
485                .then(new AnswerWithArguments() {
486                    public String answer(int netId, String name) throws Throwable {
487                        if (netId != 0) {
488                            Log.d(TAG, "Can't find var " + name + " for " + netId);
489                            return null;
490                        }
491                        String value = nameToValue.get(name);
492                        if (value != null) {
493                            Log.d(TAG, "Returning var " + name + " to " + value + " for " + netId);
494                        } else {
495                            Log.d(TAG, "Can't find var " + name + " for " + netId);
496                        }
497                        return value;
498                    }
499                });
500
501        WifiConfiguration config = new WifiConfiguration();
502        config.SSID = sSSID;
503        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
504        mLooper.startAutoDispatch();
505        mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
506        mLooper.stopAutoDispatch();
507
508        verify(mWifiNative).addNetwork();
509        verify(mWifiNative).setNetworkVariable(0, "ssid", sHexSSID);
510
511        mLooper.startAutoDispatch();
512        List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel);
513        mLooper.stopAutoDispatch();
514        assertEquals(1, configs.size());
515
516        WifiConfiguration config2 = configs.get(0);
517        assertEquals("\"GoogleGuest\"", config2.SSID);
518        assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE));
519    }
520
521    private void addNetworkAndVerifyFailure() throws Exception {
522        loadComponents();
523
524        final WifiConfiguration config = new WifiConfiguration();
525        config.SSID = sSSID;
526        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
527
528        mLooper.startAutoDispatch();
529        mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
530        mLooper.stopAutoDispatch();
531
532        verify(mWifiNative, never()).addNetwork();
533        verify(mWifiNative, never()).setNetworkVariable(anyInt(), anyString(), anyString());
534
535        mLooper.startAutoDispatch();
536        assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty());
537        mLooper.stopAutoDispatch();
538    }
539
540    /**
541     * Verifies that the current foreground user is allowed to add a network.
542     */
543    @Test
544    public void addNetworkAsCurrentUser() throws Exception {
545        addNetworkAndVerifySuccess();
546    }
547
548    /**
549     * Verifies that a managed profile of the current foreground user is allowed to add a network.
550     */
551    @Test
552    public void addNetworkAsCurrentUsersManagedProfile() throws Exception {
553        BinderUtil.setUid(MANAGED_PROFILE_UID);
554        addNetworkAndVerifySuccess();
555    }
556
557    /**
558     * Verifies that a background user is not allowed to add a network.
559     */
560    @Test
561    public void addNetworkAsOtherUser() throws Exception {
562        BinderUtil.setUid(OTHER_USER_UID);
563        addNetworkAndVerifyFailure();
564    }
565
566    private void removeNetworkAndVerifySuccess() throws Exception {
567        when(mWifiNative.removeNetwork(0)).thenReturn(true);
568        mLooper.startAutoDispatch();
569        assertTrue(mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0));
570        mLooper.stopAutoDispatch();
571
572        mLooper.startAutoDispatch();
573        assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty());
574        mLooper.stopAutoDispatch();
575    }
576
577    private void removeNetworkAndVerifyFailure() throws Exception {
578        mLooper.startAutoDispatch();
579        assertFalse(mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0));
580        mLooper.stopAutoDispatch();
581
582        mLooper.startAutoDispatch();
583        assertEquals(1, mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).size());
584        mLooper.stopAutoDispatch();
585        verify(mWifiNative, never()).removeNetwork(anyInt());
586    }
587
588    /**
589     * Verifies that the current foreground user is allowed to remove a network.
590     */
591    @Test
592    public void removeNetworkAsCurrentUser() throws Exception {
593        addNetworkAndVerifySuccess();
594        removeNetworkAndVerifySuccess();
595    }
596
597    /**
598     * Verifies that a managed profile of the current foreground user is allowed to remove a
599     * network.
600     */
601    @Test
602    public void removeNetworkAsCurrentUsersManagedProfile() throws Exception {
603        addNetworkAndVerifySuccess();
604        BinderUtil.setUid(MANAGED_PROFILE_UID);
605        removeNetworkAndVerifySuccess();
606    }
607
608    /**
609     * Verifies that a background user is not allowed to remove a network.
610     */
611    @Test
612    public void removeNetworkAsOtherUser() throws Exception {
613        addNetworkAndVerifySuccess();
614        BinderUtil.setUid(OTHER_USER_UID);
615        removeNetworkAndVerifyFailure();
616    }
617
618    private void enableNetworkAndVerifySuccess() throws Exception {
619        when(mWifiNative.enableNetwork(0, true)).thenReturn(true);
620
621        mLooper.startAutoDispatch();
622        assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
623        mLooper.stopAutoDispatch();
624
625        verify(mWifiNative).enableNetwork(0, true);
626    }
627
628    private void enableNetworkAndVerifyFailure() throws Exception {
629        mLooper.startAutoDispatch();
630        assertFalse(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
631        mLooper.stopAutoDispatch();
632
633        verify(mWifiNative, never()).enableNetwork(anyInt(), anyBoolean());
634    }
635
636    /**
637     * Verifies that the current foreground user is allowed to enable a network.
638     */
639    @Test
640    public void enableNetworkAsCurrentUser() throws Exception {
641        addNetworkAndVerifySuccess();
642        enableNetworkAndVerifySuccess();
643    }
644
645    /**
646     * Verifies that a managed profile of the current foreground user is allowed to enable a
647     * network.
648     */
649    @Test
650    public void enableNetworkAsCurrentUsersManagedProfile() throws Exception {
651        addNetworkAndVerifySuccess();
652        BinderUtil.setUid(MANAGED_PROFILE_UID);
653        enableNetworkAndVerifySuccess();
654    }
655
656    /**
657     * Verifies that a background user is not allowed to enable a network.
658     */
659    @Test
660    public void enableNetworkAsOtherUser() throws Exception {
661        addNetworkAndVerifySuccess();
662        BinderUtil.setUid(OTHER_USER_UID);
663        enableNetworkAndVerifyFailure();
664    }
665
666    private void forgetNetworkAndVerifySuccess() throws Exception {
667        when(mWifiNative.removeNetwork(0)).thenReturn(true);
668        mLooper.startAutoDispatch();
669        final Message result =
670                mWsmAsyncChannel.sendMessageSynchronously(WifiManager.FORGET_NETWORK, 0);
671        mLooper.stopAutoDispatch();
672        assertEquals(WifiManager.FORGET_NETWORK_SUCCEEDED, result.what);
673        result.recycle();
674        mLooper.startAutoDispatch();
675        assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty());
676        mLooper.stopAutoDispatch();
677    }
678
679    private void forgetNetworkAndVerifyFailure() throws Exception {
680        mLooper.startAutoDispatch();
681        final Message result =
682                mWsmAsyncChannel.sendMessageSynchronously(WifiManager.FORGET_NETWORK, 0);
683        mLooper.stopAutoDispatch();
684        assertEquals(WifiManager.FORGET_NETWORK_FAILED, result.what);
685        result.recycle();
686        mLooper.startAutoDispatch();
687        assertEquals(1, mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).size());
688        mLooper.stopAutoDispatch();
689        verify(mWifiNative, never()).removeNetwork(anyInt());
690    }
691
692    /**
693     * Verifies that the current foreground user is allowed to forget a network.
694     */
695    @Test
696    public void forgetNetworkAsCurrentUser() throws Exception {
697        addNetworkAndVerifySuccess();
698        forgetNetworkAndVerifySuccess();
699    }
700
701    /**
702     * Verifies that a managed profile of the current foreground user is allowed to forget a
703     * network.
704     */
705    @Test
706    public void forgetNetworkAsCurrentUsersManagedProfile() throws Exception {
707        addNetworkAndVerifySuccess();
708        BinderUtil.setUid(MANAGED_PROFILE_UID);
709        forgetNetworkAndVerifySuccess();
710    }
711
712    /**
713     * Verifies that a background user is not allowed to forget a network.
714     */
715    @Test
716    public void forgetNetworkAsOtherUser() throws Exception {
717        addNetworkAndVerifySuccess();
718        BinderUtil.setUid(OTHER_USER_UID);
719        forgetNetworkAndVerifyFailure();
720    }
721
722    @Test
723    public void scan() throws Exception {
724        addNetworkAndVerifySuccess();
725
726        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
727        mWsm.startScan(-1, 0, null, null);
728        mLooper.dispatchAll();
729
730        verify(mWifiNative).scan(null);
731
732        when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
733        mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
734        mLooper.dispatchAll();
735
736        List<ScanResult> results = mWsm.syncGetScanResultsList();
737        assertEquals(8, results.size());
738    }
739
740    @Test
741    public void connect() throws Exception {
742        addNetworkAndVerifySuccess();
743
744        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
745        mLooper.dispatchAll();
746
747        mLooper.startAutoDispatch();
748        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
749        mLooper.stopAutoDispatch();
750
751        verify(mWifiNative).enableNetwork(0, true);
752
753        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
754        mLooper.dispatchAll();
755
756        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
757                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
758        mLooper.dispatchAll();
759
760        assertEquals("ObtainingIpState", getCurrentState().getName());
761
762        DhcpResults dhcpResults = new DhcpResults();
763        dhcpResults.setGateway("1.2.3.4");
764        dhcpResults.setIpAddress("192.168.1.100", 0);
765        dhcpResults.addDns("8.8.8.8");
766        dhcpResults.setLeaseDuration(3600);
767
768        mLooper.startAutoDispatch();
769        mTestIpManager.injectDhcpSuccess(dhcpResults);
770        mLooper.stopAutoDispatch();
771
772        assertEquals("ConnectedState", getCurrentState().getName());
773    }
774
775    @Test
776    public void testDhcpFailure() throws Exception {
777        addNetworkAndVerifySuccess();
778
779        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
780        mLooper.dispatchAll();
781
782        mLooper.startAutoDispatch();
783        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
784        mLooper.stopAutoDispatch();
785
786        verify(mWifiNative).enableNetwork(0, true);
787
788        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
789        mLooper.dispatchAll();
790
791        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
792                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
793        mLooper.dispatchAll();
794
795        assertEquals("ObtainingIpState", getCurrentState().getName());
796
797        mLooper.startAutoDispatch();
798        mTestIpManager.injectDhcpFailure();
799        mLooper.stopAutoDispatch();
800
801        assertEquals("DisconnectingState", getCurrentState().getName());
802    }
803
804    @Test
805    public void testBadNetworkEvent() throws Exception {
806        addNetworkAndVerifySuccess();
807
808        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
809        mLooper.dispatchAll();
810
811        mLooper.startAutoDispatch();
812        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
813        mLooper.stopAutoDispatch();
814
815        verify(mWifiNative).enableNetwork(0, true);
816
817        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID);
818        mLooper.dispatchAll();
819
820        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
821                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
822        mLooper.dispatchAll();
823
824        assertEquals("DisconnectedState", getCurrentState().getName());
825    }
826
827
828    @Test
829    public void smToString() throws Exception {
830        assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString(
831                AsyncChannel.CMD_CHANNEL_HALF_CONNECTED));
832        assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString(
833                DhcpClient.CMD_PRE_DHCP_ACTION));
834        assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString(
835                WifiStateMachine.CMD_IP_REACHABILITY_LOST));
836    }
837
838    @Test
839    public void disconnect() throws Exception {
840        connect();
841
842        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06");
843        mLooper.dispatchAll();
844        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
845                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED));
846        mLooper.dispatchAll();
847
848        assertEquals("DisconnectedState", getCurrentState().getName());
849    }
850
851    @Test
852    public void handleUserSwitch() throws Exception {
853        assertEquals(UserHandle.USER_SYSTEM, mWsm.getCurrentUserId());
854
855        mWsm.handleUserSwitch(10);
856        mLooper.dispatchAll();
857
858        assertEquals(10, mWsm.getCurrentUserId());
859    }
860
861    @Test
862    public void iconQueryTest() throws Exception {
863        /* enable wi-fi */
864        addNetworkAndVerifySuccess();
865
866        long bssid = 0x1234567800FFL;
867        String filename = "iconFileName.png";
868        String command = "REQ_HS20_ICON " + Utils.macToString(bssid) + " " + filename;
869
870        when(mWifiNative.doCustomSupplicantCommand(command)).thenReturn("OK");
871
872        mLooper.startAutoDispatch();
873        boolean result = mWsm.syncQueryPasspointIcon(mWsmAsyncChannel, bssid, filename);
874        mLooper.stopAutoDispatch();
875
876        verify(mWifiNative).doCustomSupplicantCommand(command);
877        assertEquals(true, result);
878    }
879}
880