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