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