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