WifiStateMachineTest.java revision 17c2a7b30e5680b11fc0073ce322ee7bc14ef2c5
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.assertNull;
22import static org.junit.Assert.assertTrue;
23import static org.mockito.Mockito.*;
24
25import android.app.ActivityManager;
26import android.app.test.MockAnswerUtil.AnswerWithArguments;
27import android.app.test.TestAlarmManager;
28import android.content.Context;
29import android.content.pm.PackageManager;
30import android.content.pm.UserInfo;
31import android.content.res.Resources;
32import android.net.ConnectivityManager;
33import android.net.DhcpResults;
34import android.net.LinkProperties;
35import android.net.dhcp.DhcpClient;
36import android.net.ip.IpManager;
37import android.net.wifi.IApInterface;
38import android.net.wifi.IClientInterface;
39import android.net.wifi.IWificond;
40import android.net.wifi.ScanResult;
41import android.net.wifi.SupplicantState;
42import android.net.wifi.WifiConfiguration;
43import android.net.wifi.WifiInfo;
44import android.net.wifi.WifiManager;
45import android.net.wifi.WifiScanner;
46import android.net.wifi.WifiSsid;
47import android.net.wifi.WpsInfo;
48import android.net.wifi.hotspot2.PasspointConfiguration;
49import android.net.wifi.hotspot2.pps.HomeSp;
50import android.net.wifi.p2p.IWifiP2pManager;
51import android.os.BatteryStats;
52import android.os.Binder;
53import android.os.Bundle;
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.RemoteException;
65import android.os.UserHandle;
66import android.os.UserManager;
67import android.os.test.TestLooper;
68import android.provider.Settings;
69import android.security.KeyStore;
70import android.test.mock.MockContentProvider;
71import android.test.mock.MockContentResolver;
72import android.test.suitebuilder.annotation.SmallTest;
73import android.util.Log;
74import android.util.SparseArray;
75
76import com.android.internal.R;
77import com.android.internal.app.IBatteryStats;
78import com.android.internal.util.AsyncChannel;
79import com.android.internal.util.IState;
80import com.android.internal.util.StateMachine;
81import com.android.server.wifi.hotspot2.NetworkDetail;
82import com.android.server.wifi.hotspot2.PasspointManager;
83import com.android.server.wifi.p2p.WifiP2pServiceImpl;
84
85import org.junit.After;
86import org.junit.Before;
87import org.junit.Test;
88import org.mockito.ArgumentCaptor;
89import org.mockito.Mock;
90import org.mockito.MockitoAnnotations;
91
92import java.io.ByteArrayOutputStream;
93import java.io.PrintWriter;
94import java.lang.reflect.Field;
95import java.lang.reflect.InvocationTargetException;
96import java.lang.reflect.Method;
97import java.util.ArrayList;
98import java.util.Arrays;
99import java.util.HashSet;
100import java.util.List;
101import java.util.Map;
102import java.util.Set;
103import java.util.concurrent.CountDownLatch;
104
105/**
106 * Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
107 */
108@SmallTest
109public class WifiStateMachineTest {
110    public static final String TAG = "WifiStateMachineTest";
111
112    private static final int MANAGED_PROFILE_UID = 1100000;
113    private static final int OTHER_USER_UID = 1200000;
114    private static final int LOG_REC_LIMIT_IN_VERBOSE_MODE =
115            (ActivityManager.isLowRamDeviceStatic()
116                    ? WifiStateMachine.NUM_LOG_RECS_VERBOSE_LOW_MEMORY
117                    : WifiStateMachine.NUM_LOG_RECS_VERBOSE);
118    private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
119
120    private long mBinderToken;
121
122    private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) {
123        return mock(class1, withSettings().extraInterfaces(interfaces));
124    }
125
126    private static <T, I> IBinder mockService(Class<T> class1, Class<I> iface) {
127        T tImpl = mockWithInterfaces(class1, iface);
128        IBinder binder = mock(IBinder.class);
129        when(((IInterface) tImpl).asBinder()).thenReturn(binder);
130        when(binder.queryLocalInterface(iface.getCanonicalName()))
131                .thenReturn((IInterface) tImpl);
132        return binder;
133    }
134
135    private void enableDebugLogs() {
136        mWsm.enableVerboseLogging(1);
137    }
138
139    private class TestIpManager extends IpManager {
140        TestIpManager(Context context, String ifname, IpManager.Callback callback) {
141            // Call dependency-injection superclass constructor.
142            super(context, ifname, callback, mock(INetworkManagementService.class));
143        }
144
145        @Override
146        public void startProvisioning(IpManager.ProvisioningConfiguration config) {}
147
148        @Override
149        public void stop() {}
150
151        @Override
152        public void confirmConfiguration() {}
153
154        void injectDhcpSuccess(DhcpResults dhcpResults) {
155            mCallback.onNewDhcpResults(dhcpResults);
156            mCallback.onProvisioningSuccess(new LinkProperties());
157        }
158
159        void injectDhcpFailure() {
160            mCallback.onNewDhcpResults(null);
161            mCallback.onProvisioningFailure(new LinkProperties());
162        }
163    }
164
165    private FrameworkFacade getFrameworkFacade() throws Exception {
166        FrameworkFacade facade = mock(FrameworkFacade.class);
167
168        when(facade.getService(Context.NETWORKMANAGEMENT_SERVICE)).thenReturn(
169                mockWithInterfaces(IBinder.class, INetworkManagementService.class));
170
171        IBinder p2pBinder = mockService(WifiP2pServiceImpl.class, IWifiP2pManager.class);
172        when(facade.getService(Context.WIFI_P2P_SERVICE)).thenReturn(p2pBinder);
173
174        WifiP2pServiceImpl p2pm = (WifiP2pServiceImpl) p2pBinder.queryLocalInterface(
175                IWifiP2pManager.class.getCanonicalName());
176
177        final CountDownLatch untilDone = new CountDownLatch(1);
178        mP2pThread = new HandlerThread("WifiP2pMockThread") {
179            @Override
180            protected void onLooperPrepared() {
181                untilDone.countDown();
182            }
183        };
184
185        mP2pThread.start();
186        untilDone.await();
187
188        Handler handler = new Handler(mP2pThread.getLooper());
189        when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler));
190
191        IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
192        when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
193
194        when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class)))
195                .then(new AnswerWithArguments() {
196                    public IpManager answer(
197                            Context context, String ifname, IpManager.Callback callback) {
198                        mTestIpManager = new TestIpManager(context, ifname, callback);
199                        return mTestIpManager;
200                    }
201                });
202
203        return facade;
204    }
205
206    private Context getContext() throws Exception {
207        PackageManager pkgMgr = mock(PackageManager.class);
208        when(pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
209
210        Context context = mock(Context.class);
211        when(context.getPackageManager()).thenReturn(pkgMgr);
212
213        MockResources resources = new com.android.server.wifi.MockResources();
214        when(context.getResources()).thenReturn(resources);
215
216        MockContentResolver mockContentResolver = new MockContentResolver();
217        mockContentResolver.addProvider(Settings.AUTHORITY,
218                new MockContentProvider(context) {
219                    @Override
220                    public Bundle call(String method, String arg, Bundle extras) {
221                        return new Bundle();
222                    }
223                });
224        when(context.getContentResolver()).thenReturn(mockContentResolver);
225
226        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(
227                new PowerManager(context, mock(IPowerManager.class), new Handler()));
228
229        mAlarmManager = new TestAlarmManager();
230        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
231                mAlarmManager.getAlarmManager());
232
233        when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
234                mock(ConnectivityManager.class));
235
236        return context;
237    }
238
239    private Resources getMockResources() {
240        MockResources resources = new MockResources();
241        resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false);
242        return resources;
243    }
244
245    private IState getCurrentState() throws
246            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
247        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
248        method.setAccessible(true);
249        return (IState) method.invoke(mWsm);
250    }
251
252    private static HandlerThread getWsmHandlerThread(WifiStateMachine wsm) throws
253            NoSuchFieldException, InvocationTargetException, IllegalAccessException {
254        Field field = StateMachine.class.getDeclaredField("mSmThread");
255        field.setAccessible(true);
256        return (HandlerThread) field.get(wsm);
257    }
258
259    private static void stopLooper(final Looper looper) throws Exception {
260        new Handler(looper).post(new Runnable() {
261            @Override
262            public void run() {
263                looper.quitSafely();
264            }
265        });
266    }
267
268    private void dumpState() {
269        ByteArrayOutputStream stream = new ByteArrayOutputStream();
270        PrintWriter writer = new PrintWriter(stream);
271        mWsm.dump(null, writer, null);
272        writer.flush();
273        Log.d(TAG, "WifiStateMachine state -" + stream.toString());
274    }
275
276    private static ScanDetail getGoogleGuestScanDetail(int rssi) {
277        ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
278        ie[0] = ScanResults.generateSsidIe(sSSID);
279        NetworkDetail nd = new NetworkDetail(sBSSID, ie, new ArrayList<String>(), sFreq);
280        ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq,
281                Long.MAX_VALUE, /* needed so that scan results aren't rejected because
282                                   there older than scan start */
283                ie, new ArrayList<String>());
284        return detail;
285    }
286
287    private ArrayList<ScanDetail> getMockScanResults() {
288        ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
289        ArrayList<ScanDetail> list = sr.getScanDetailArrayList();
290
291        int rssi = -65;
292        list.add(getGoogleGuestScanDetail(rssi));
293        return list;
294    }
295
296    static final String   sSSID = "\"GoogleGuest\"";
297    static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
298    static final String   sHexSSID = sWifiSsid.getHexString().replace("0x", "").replace("22", "");
299    static final String   sBSSID = "01:02:03:04:05:06";
300    static final int      sFreq = 2437;
301
302    WifiStateMachine mWsm;
303    HandlerThread mWsmThread;
304    HandlerThread mP2pThread;
305    HandlerThread mSyncThread;
306    AsyncChannel  mWsmAsyncChannel;
307    TestAlarmManager mAlarmManager;
308    MockWifiMonitor mWifiMonitor;
309    TestIpManager mTestIpManager;
310    TestLooper mLooper;
311
312    @Mock WifiScanner mWifiScanner;
313    @Mock SupplicantStateTracker mSupplicantStateTracker;
314    @Mock WifiMetrics mWifiMetrics;
315    @Mock UserManager mUserManager;
316    @Mock WifiApConfigStore mApConfigStore;
317    @Mock BackupManagerProxy mBackupManagerProxy;
318    @Mock WifiCountryCode mCountryCode;
319    @Mock WifiInjector mWifiInjector;
320    @Mock WifiLastResortWatchdog mWifiLastResortWatchdog;
321    @Mock PropertyService mPropertyService;
322    @Mock BuildProperties mBuildProperties;
323    @Mock IWificond mWificond;
324    @Mock IApInterface mApInterface;
325    @Mock IClientInterface mClientInterface;
326    @Mock IBinder mApInterfaceBinder;
327    @Mock IBinder mClientInterfaceBinder;
328    @Mock WifiConfigManager mWifiConfigManager;
329    @Mock WifiNative mWifiNative;
330    @Mock WifiConnectivityManager mWifiConnectivityManager;
331    @Mock SoftApManager mSoftApManager;
332    @Mock WifiStateTracker mWifiStateTracker;
333    @Mock PasspointManager mPasspointManager;
334
335    public WifiStateMachineTest() throws Exception {
336    }
337
338    @Before
339    public void setUp() throws Exception {
340        Log.d(TAG, "Setting up ...");
341
342        // Ensure looper exists
343        mLooper = new TestLooper();
344
345        MockitoAnnotations.initMocks(this);
346
347        /** uncomment this to enable logs from WifiStateMachines */
348        // enableDebugLogs();
349
350        mWifiMonitor = new MockWifiMonitor();
351        when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
352        when(mWifiInjector.getClock()).thenReturn(new Clock());
353        when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog);
354        when(mWifiInjector.getPropertyService()).thenReturn(mPropertyService);
355        when(mWifiInjector.getBuildProperties()).thenReturn(mBuildProperties);
356        when(mWifiInjector.getKeyStore()).thenReturn(mock(KeyStore.class));
357        when(mWifiInjector.getWifiBackupRestore()).thenReturn(mock(WifiBackupRestore.class));
358        when(mWifiInjector.makeWifiDiagnostics(anyObject())).thenReturn(
359                mock(BaseWifiDiagnostics.class));
360        when(mWifiInjector.makeWificond()).thenReturn(mWificond);
361        when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager);
362        when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
363        when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
364                .thenReturn(mWifiConnectivityManager);
365        when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
366                any(SoftApManager.Listener.class), any(IApInterface.class),
367                any(WifiConfiguration.class)))
368                .thenReturn(mSoftApManager);
369        when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
370        when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
371        when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor);
372        when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
373
374        when(mWifiNative.setupForClientMode()).thenReturn(mClientInterface);
375        when(mWifiNative.setupForSoftApMode()).thenReturn(mApInterface);
376        when(mWifiNative.getInterfaceName()).thenReturn("mockWlan");
377        when(mWifiNative.enableSupplicant()).thenReturn(true);
378        when(mWifiNative.disableSupplicant()).thenReturn(true);
379        when(mWifiNative.getFrameworkNetworkId(anyInt())).thenReturn(0);
380
381
382        FrameworkFacade factory = getFrameworkFacade();
383        Context context = getContext();
384
385        Resources resources = getMockResources();
386        when(context.getResources()).thenReturn(resources);
387
388        when(factory.getIntegerSetting(context,
389                Settings.Global.WIFI_FREQUENCY_BAND,
390                WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn(
391                WifiManager.WIFI_FREQUENCY_BAND_AUTO);
392
393        when(factory.makeApConfigStore(eq(context), eq(mBackupManagerProxy)))
394                .thenReturn(mApConfigStore);
395
396        when(factory.makeSupplicantStateTracker(
397                any(Context.class), any(WifiConfigManager.class),
398                any(Handler.class))).thenReturn(mSupplicantStateTracker);
399
400        when(mUserManager.getProfileParent(11))
401                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0));
402        when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList(
403                new UserInfo(UserHandle.USER_SYSTEM, "owner", 0),
404                new UserInfo(11, "managed profile", 0)));
405
406        when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
407        when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder);
408
409        mWsm = new WifiStateMachine(context, factory, mLooper.getLooper(),
410            mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative);
411        mWsmThread = getWsmHandlerThread(mWsm);
412
413        final AsyncChannel channel = new AsyncChannel();
414        Handler handler = new Handler(mLooper.getLooper()) {
415            @Override
416            public void handleMessage(Message msg) {
417                switch (msg.what) {
418                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
419                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
420                            mWsmAsyncChannel = channel;
421                        } else {
422                            Log.d(TAG, "Failed to connect Command channel " + this);
423                        }
424                        break;
425                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
426                        Log.d(TAG, "Command channel disconnected" + this);
427                        break;
428                }
429            }
430        };
431
432        channel.connect(context, handler, mWsm.getMessenger());
433        mLooper.dispatchAll();
434        /* Now channel is supposed to be connected */
435
436        mBinderToken = Binder.clearCallingIdentity();
437    }
438
439    @After
440    public void cleanUp() throws Exception {
441        Binder.restoreCallingIdentity(mBinderToken);
442
443        if (mSyncThread != null) stopLooper(mSyncThread.getLooper());
444        if (mWsmThread != null) stopLooper(mWsmThread.getLooper());
445        if (mP2pThread != null) stopLooper(mP2pThread.getLooper());
446
447        mWsmThread = null;
448        mP2pThread = null;
449        mSyncThread = null;
450        mWsmAsyncChannel = null;
451        mWsm = null;
452    }
453
454    @Test
455    public void createNew() throws Exception {
456        assertEquals("InitialState", getCurrentState().getName());
457
458        mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
459        mLooper.dispatchAll();
460        assertEquals("InitialState", getCurrentState().getName());
461    }
462
463    @Test
464    public void loadComponentsInStaMode() throws Exception {
465        startSupplicantAndDispatchMessages();
466
467        assertEquals("DisconnectedState", getCurrentState().getName());
468    }
469
470    @Test
471    public void loadComponentsInApMode() throws Exception {
472        mWsm.setHostApRunning(new WifiConfiguration(), true);
473        mLooper.dispatchAll();
474
475        assertEquals("SoftApState", getCurrentState().getName());
476
477        verify(mSoftApManager).start();
478    }
479
480    @Test
481    public void shouldRequireSupplicantStartupToLeaveInitialState() throws Exception {
482        when(mWifiNative.enableSupplicant()).thenReturn(false);
483        mWsm.setSupplicantRunning(true);
484        mLooper.dispatchAll();
485        assertEquals("InitialState", getCurrentState().getName());
486    }
487
488    @Test
489    public void shouldRequireWificondToLeaveInitialState() throws Exception {
490        // We start out with valid default values, break them going backwards so that
491        // we test all the bailout cases.
492
493        // ClientInterface dies after creation.
494        doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt());
495        mWsm.setSupplicantRunning(true);
496        mLooper.dispatchAll();
497        assertEquals("InitialState", getCurrentState().getName());
498
499        // Failed to even create the client interface.
500        when(mWificond.createClientInterface()).thenReturn(null);
501        mWsm.setSupplicantRunning(true);
502        mLooper.dispatchAll();
503        assertEquals("InitialState", getCurrentState().getName());
504
505        // Failed to get wificond proxy.
506        when(mWifiInjector.makeWificond()).thenReturn(null);
507        mWsm.setSupplicantRunning(true);
508        mLooper.dispatchAll();
509        assertEquals("InitialState", getCurrentState().getName());
510    }
511
512    @Test
513    public void loadComponentsFailure() throws Exception {
514        when(mWifiNative.startHal(anyBoolean())).thenReturn(false);
515        when(mWifiNative.enableSupplicant()).thenReturn(false);
516
517        mWsm.setSupplicantRunning(true);
518        mLooper.dispatchAll();
519        assertEquals("InitialState", getCurrentState().getName());
520
521        when(mWifiNative.startHal(anyBoolean())).thenReturn(true);
522        mWsm.setSupplicantRunning(true);
523        mLooper.dispatchAll();
524        assertEquals("InitialState", getCurrentState().getName());
525    }
526
527    @Test
528    public void checkInitialStateStickyWhenDisabledMode() throws Exception {
529        mLooper.dispatchAll();
530        assertEquals("InitialState", getCurrentState().getName());
531        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
532
533        mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE);
534        mLooper.dispatchAll();
535        assertEquals(WifiStateMachine.DISABLED_MODE, mWsm.getOperationalModeForTest());
536        assertEquals("InitialState", getCurrentState().getName());
537    }
538
539    @Test
540    public void shouldStartSupplicantWhenConnectModeRequested() throws Exception {
541        when(mWifiNative.startHal(anyBoolean())).thenReturn(true);
542
543        // The first time we start out in InitialState, we sit around here.
544        mLooper.dispatchAll();
545        assertEquals("InitialState", getCurrentState().getName());
546        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
547
548        // But if someone tells us to enter connect mode, we start up supplicant
549        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
550        mLooper.dispatchAll();
551        assertEquals("SupplicantStartingState", getCurrentState().getName());
552    }
553
554    /**
555     *  Test that mode changes accurately reflect the value for isWifiEnabled.
556     */
557    @Test
558    public void checkIsWifiEnabledForModeChanges() throws Exception {
559        when(mWifiNative.startHal(anyBoolean())).thenReturn(true);
560
561        // Check initial state
562        mLooper.dispatchAll();
563        assertEquals("InitialState", getCurrentState().getName());
564        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
565
566        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
567        startSupplicantAndDispatchMessages();
568        mWsm.setSupplicantRunning(true);
569        mLooper.dispatchAll();
570        assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
571        assertEquals("ScanModeState", getCurrentState().getName());
572        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
573
574        // switch to connect mode and verify wifi is reported as enabled
575        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
576        mLooper.dispatchAll();
577        assertEquals("DisconnectedState", getCurrentState().getName());
578        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
579        assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
580
581        // now go back to scan mode with "wifi disabled" to verify the reported wifi state.
582        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
583        mLooper.dispatchAll();
584        assertEquals(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE,
585                     mWsm.getOperationalModeForTest());
586        assertEquals("ScanModeState", getCurrentState().getName());
587        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
588
589        // now go to AP mode
590        mWsm.setSupplicantRunning(false);
591        mWsm.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
592        mWsm.sendMessage(WifiMonitor.SUP_DISCONNECTION_EVENT);
593        mWsm.setHostApRunning(new WifiConfiguration(), true);
594        mLooper.dispatchAll();
595        assertEquals("SoftApState", getCurrentState().getName());
596        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
597    }
598
599
600    /**
601     * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant
602     * is started.
603     */
604    @Test
605    public void checkStartInCorrectStateAfterChangingInitialState() throws Exception {
606        when(mWifiNative.startHal(anyBoolean())).thenReturn(true);
607
608        // Check initial state
609        mLooper.dispatchAll();
610        assertEquals("InitialState", getCurrentState().getName());
611        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
612
613        // Update the mode
614        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
615        mLooper.dispatchAll();
616        assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
617
618        // Start supplicant so we move to the next state
619        startSupplicantAndDispatchMessages();
620
621        assertEquals("ScanModeState", getCurrentState().getName());
622    }
623
624    /**
625     * Verifies that configs can be removed when in client mode.
626     */
627    @Test
628    public void canRemoveNetworkConfigInClientMode() throws Exception {
629        boolean result;
630        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
631        addNetworkAndVerifySuccess();
632        mLooper.startAutoDispatch();
633        result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
634        mLooper.stopAutoDispatch();
635        assertTrue(result);
636    }
637
638    /**
639     * Verifies that configs can be removed when not in client mode.
640     */
641    @Test
642    public void canRemoveNetworkConfigWhenWifiDisabled() {
643        boolean result;
644        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
645        mLooper.startAutoDispatch();
646        result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
647        mLooper.stopAutoDispatch();
648
649        assertTrue(result);
650        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
651    }
652
653    /**
654     * Verifies that configs can be forgotten when in client mode.
655     */
656    @Test
657    public void canForgetNetworkConfigInClientMode() throws Exception {
658        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
659        addNetworkAndVerifySuccess();
660        mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
661        mLooper.dispatchAll();
662        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
663    }
664
665    /**
666     * Verifies that configs can be removed when not in client mode.
667     */
668    @Test
669    public void canForgetNetworkConfigWhenWifiDisabled() throws Exception {
670        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
671        mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
672        mLooper.dispatchAll();
673        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
674    }
675
676    /**
677     * Helper method to move through SupplicantStarting and SupplicantStarted states.
678     */
679    private void startSupplicantAndDispatchMessages() throws Exception {
680        mWsm.setSupplicantRunning(true);
681        mLooper.dispatchAll();
682
683        assertEquals("SupplicantStartingState", getCurrentState().getName());
684
685        when(mWifiNative.setDeviceName(anyString())).thenReturn(true);
686        when(mWifiNative.setManufacturer(anyString())).thenReturn(true);
687        when(mWifiNative.setModelName(anyString())).thenReturn(true);
688        when(mWifiNative.setModelNumber(anyString())).thenReturn(true);
689        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
690        when(mWifiNative.setConfigMethods(anyString())).thenReturn(true);
691        when(mWifiNative.setDeviceType(anyString())).thenReturn(true);
692        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
693        when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true);
694
695        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
696        mLooper.dispatchAll();
697    }
698
699    private void addNetworkAndVerifySuccess() throws Exception {
700        addNetworkAndVerifySuccess(false);
701    }
702
703    private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception {
704        loadComponentsInStaMode();
705
706        WifiConfiguration config = new WifiConfiguration();
707        config.SSID = sSSID;
708        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
709        config.hiddenSSID = isHidden;
710
711        when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
712                .thenReturn(new NetworkUpdateResult(0));
713        when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config));
714        when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config);
715
716        mLooper.startAutoDispatch();
717        mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
718        mLooper.stopAutoDispatch();
719
720        verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt());
721
722        mLooper.startAutoDispatch();
723        List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel);
724        mLooper.stopAutoDispatch();
725        assertEquals(1, configs.size());
726
727        WifiConfiguration config2 = configs.get(0);
728        assertEquals("\"GoogleGuest\"", config2.SSID);
729        assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE));
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    private void verifyScan(int band, int reportEvents, Set<String> hiddenNetworkSSIDSet) {
751        ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor =
752                ArgumentCaptor.forClass(WifiScanner.ScanSettings.class);
753        ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor =
754                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
755        verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture(),
756                eq(null));
757        WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue();
758        assertEquals("band", band, actualSettings.band);
759        assertEquals("reportEvents", reportEvents, actualSettings.reportEvents);
760
761        if (hiddenNetworkSSIDSet == null) {
762            hiddenNetworkSSIDSet = new HashSet<>();
763        }
764        Set<String> actualHiddenNetworkSSIDSet = new HashSet<>();
765        if (actualSettings.hiddenNetworks != null) {
766            for (int i = 0; i < actualSettings.hiddenNetworks.length; ++i) {
767                actualHiddenNetworkSSIDSet.add(actualSettings.hiddenNetworks[i].ssid);
768            }
769        }
770        assertEquals("hidden networks", hiddenNetworkSSIDSet, actualHiddenNetworkSSIDSet);
771
772        when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
773        mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
774
775        mLooper.dispatchAll();
776
777        List<ScanResult> reportedResults = mWsm.syncGetScanResultsList();
778        assertEquals(8, reportedResults.size());
779    }
780
781    @Test
782    public void scan() throws Exception {
783        addNetworkAndVerifySuccess();
784
785        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
786        mWsm.startScan(-1, 0, null, null);
787        mLooper.dispatchAll();
788
789        verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
790                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
791                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null);
792    }
793
794    @Test
795    public void scanWithHiddenNetwork() throws Exception {
796        addNetworkAndVerifySuccess(true);
797
798        Set<String> hiddenNetworkSet = new HashSet<>();
799        hiddenNetworkSet.add(sSSID);
800        List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
801        hiddenNetworkList.add(new WifiScanner.ScanSettings.HiddenNetwork(sSSID));
802        when(mWifiConfigManager.retrieveHiddenNetworkList()).thenReturn(hiddenNetworkList);
803
804        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
805        mWsm.startScan(-1, 0, null, null);
806        mLooper.dispatchAll();
807
808        verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
809                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
810                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
811                hiddenNetworkSet);
812    }
813
814    @Test
815    public void connect() throws Exception {
816        addNetworkAndVerifySuccess();
817        when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(true);
818        when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(true);
819
820        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
821        mLooper.dispatchAll();
822        verify(mWifiNative).removeAllNetworks();
823
824        mLooper.startAutoDispatch();
825        assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
826        mLooper.stopAutoDispatch();
827
828        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
829        verify(mWifiConnectivityManager).setUserConnectChoice(eq(0));
830
831        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
832        mLooper.dispatchAll();
833
834        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
835                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
836        mLooper.dispatchAll();
837
838        assertEquals("ObtainingIpState", getCurrentState().getName());
839
840        DhcpResults dhcpResults = new DhcpResults();
841        dhcpResults.setGateway("1.2.3.4");
842        dhcpResults.setIpAddress("192.168.1.100", 0);
843        dhcpResults.addDns("8.8.8.8");
844        dhcpResults.setLeaseDuration(3600);
845
846        mTestIpManager.injectDhcpSuccess(dhcpResults);
847        mLooper.dispatchAll();
848
849        assertEquals("ConnectedState", getCurrentState().getName());
850    }
851
852    @Test
853    public void connectWithNoEnablePermission() throws Exception {
854        addNetworkAndVerifySuccess();
855        when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(false);
856        when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(false);
857
858        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
859        mLooper.dispatchAll();
860        verify(mWifiNative).removeAllNetworks();
861
862        mLooper.startAutoDispatch();
863        assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
864        mLooper.stopAutoDispatch();
865
866        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
867        verify(mWifiConnectivityManager, never()).setUserConnectChoice(eq(0));
868
869        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
870        mLooper.dispatchAll();
871
872        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
873                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
874        mLooper.dispatchAll();
875
876        assertEquals("ObtainingIpState", getCurrentState().getName());
877
878        DhcpResults dhcpResults = new DhcpResults();
879        dhcpResults.setGateway("1.2.3.4");
880        dhcpResults.setIpAddress("192.168.1.100", 0);
881        dhcpResults.addDns("8.8.8.8");
882        dhcpResults.setLeaseDuration(3600);
883
884        mTestIpManager.injectDhcpSuccess(dhcpResults);
885        mLooper.dispatchAll();
886
887        assertEquals("ConnectedState", getCurrentState().getName());
888    }
889
890    @Test
891    public void enableWithInvalidNetworkId() throws Exception {
892        addNetworkAndVerifySuccess();
893        when(mWifiConfigManager.getConfiguredNetwork(eq(0))).thenReturn(null);
894
895        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
896        mLooper.dispatchAll();
897        verify(mWifiNative).removeAllNetworks();
898
899        mLooper.startAutoDispatch();
900        assertFalse(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
901        mLooper.stopAutoDispatch();
902
903        verify(mWifiConfigManager, never()).enableNetwork(eq(0), eq(true), anyInt());
904        verify(mWifiConfigManager, never()).checkAndUpdateLastConnectUid(eq(0), anyInt());
905    }
906
907    /**
908     * If caller tries to connect to a network that is already connected, the connection request
909     * should succeed.
910     *
911     * Test: Create and connect to a network, then try to reconnect to the same network. Verify
912     * that connection request returns with CONNECT_NETWORK_SUCCEEDED.
913     */
914    @Test
915    public void reconnectToConnectedNetwork() throws Exception {
916        addNetworkAndVerifySuccess();
917
918        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
919        mLooper.dispatchAll();
920        verify(mWifiNative).removeAllNetworks();
921
922        mLooper.startAutoDispatch();
923        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
924        mLooper.stopAutoDispatch();
925
926        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
927
928        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
929        mLooper.dispatchAll();
930
931        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
932                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
933        mLooper.dispatchAll();
934
935        assertEquals("ObtainingIpState", getCurrentState().getName());
936
937        // try to reconnect
938        mLooper.startAutoDispatch();
939        Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.CONNECT_NETWORK, 0);
940        mLooper.stopAutoDispatch();
941
942        assertEquals(WifiManager.CONNECT_NETWORK_SUCCEEDED, reply.what);
943    }
944
945    @Test
946    public void testDhcpFailure() throws Exception {
947        addNetworkAndVerifySuccess();
948
949        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
950        mLooper.dispatchAll();
951
952        mLooper.startAutoDispatch();
953        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
954        mLooper.stopAutoDispatch();
955
956        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
957
958        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
959        mLooper.dispatchAll();
960
961        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
962                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
963        mLooper.dispatchAll();
964
965        assertEquals("ObtainingIpState", getCurrentState().getName());
966
967        mTestIpManager.injectDhcpFailure();
968        mLooper.dispatchAll();
969
970        assertEquals("DisconnectingState", getCurrentState().getName());
971    }
972
973    @Test
974    public void testBadNetworkEvent() throws Exception {
975        addNetworkAndVerifySuccess();
976
977        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
978        mLooper.dispatchAll();
979
980        mLooper.startAutoDispatch();
981        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
982        mLooper.stopAutoDispatch();
983
984        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
985
986        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID);
987        mLooper.dispatchAll();
988
989        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
990                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
991        mLooper.dispatchAll();
992
993        assertEquals("DisconnectedState", getCurrentState().getName());
994    }
995
996
997    @Test
998    public void smToString() throws Exception {
999        assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString(
1000                AsyncChannel.CMD_CHANNEL_HALF_CONNECTED));
1001        assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString(
1002                DhcpClient.CMD_PRE_DHCP_ACTION));
1003        assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString(
1004                WifiStateMachine.CMD_IP_REACHABILITY_LOST));
1005    }
1006
1007    @Test
1008    public void disconnect() throws Exception {
1009        connect();
1010
1011        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06");
1012        mLooper.dispatchAll();
1013        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1014                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED));
1015        mLooper.dispatchAll();
1016
1017        assertEquals("DisconnectedState", getCurrentState().getName());
1018    }
1019
1020    /**
1021     * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected
1022     * to true.
1023     *
1024     * Test: Successfully create and connect to a network. Check the config and verify
1025     * WifiConfiguration.getHasEverConnected() is true.
1026     */
1027    @Test
1028    public void setHasEverConnectedTrueOnConnect() throws Exception {
1029        connect();
1030        verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(0);
1031    }
1032
1033    /**
1034     * Fail network connection attempt and verify HasEverConnected remains false.
1035     *
1036     * Test: Successfully create a network but fail when connecting. Check the config and verify
1037     * WifiConfiguration.getHasEverConnected() is false.
1038     */
1039    @Test
1040    public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception {
1041        testDhcpFailure();
1042        verify(mWifiConfigManager, never()).updateNetworkAfterConnect(0);
1043    }
1044
1045    @Test
1046    public void iconQueryTest() throws Exception {
1047        // TODO(b/31065385): Passpoint config management.
1048    }
1049
1050    @Test
1051    public void verboseLogRecSizeIsGreaterThanNormalSize() {
1052        assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > WifiStateMachine.NUM_LOG_RECS_NORMAL);
1053    }
1054
1055    /**
1056     * Verifies that, by default, we allow only the "normal" number of log records.
1057     */
1058    @Test
1059    public void normalLogRecSizeIsUsedByDefault() {
1060        assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize());
1061    }
1062
1063    /**
1064     * Verifies that, in verbose mode, we allow a larger number of log records.
1065     */
1066    @Test
1067    public void enablingVerboseLoggingUpdatesLogRecSize() {
1068        mWsm.enableVerboseLogging(1);
1069        assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecMaxSize());
1070    }
1071
1072    @Test
1073    public void disablingVerboseLoggingClearsRecords() {
1074        mWsm.sendMessage(WifiStateMachine.CMD_DISCONNECT);
1075        mLooper.dispatchAll();
1076        assertTrue(mWsm.getLogRecSize() >= 1);
1077
1078        mWsm.enableVerboseLogging(0);
1079        assertEquals(0, mWsm.getLogRecSize());
1080    }
1081
1082    @Test
1083    public void disablingVerboseLoggingUpdatesLogRecSize() {
1084        mWsm.enableVerboseLogging(1);
1085        mWsm.enableVerboseLogging(0);
1086        assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize());
1087    }
1088
1089    /** Verifies that enabling verbose logging sets the hal log property in eng builds. */
1090    @Test
1091    public void enablingVerboseLoggingSetsHalLogPropertyInEngBuilds() {
1092        reset(mPropertyService);  // Ignore calls made in setUp()
1093        when(mBuildProperties.isEngBuild()).thenReturn(true);
1094        when(mBuildProperties.isUserdebugBuild()).thenReturn(false);
1095        when(mBuildProperties.isUserBuild()).thenReturn(false);
1096        mWsm.enableVerboseLogging(1);
1097        verify(mPropertyService).set("log.tag.WifiHAL", "V");
1098    }
1099
1100    /** Verifies that enabling verbose logging sets the hal log property in userdebug builds. */
1101    @Test
1102    public void enablingVerboseLoggingSetsHalLogPropertyInUserdebugBuilds() {
1103        reset(mPropertyService);  // Ignore calls made in setUp()
1104        when(mBuildProperties.isUserdebugBuild()).thenReturn(true);
1105        when(mBuildProperties.isEngBuild()).thenReturn(false);
1106        when(mBuildProperties.isUserBuild()).thenReturn(false);
1107        mWsm.enableVerboseLogging(1);
1108        verify(mPropertyService).set("log.tag.WifiHAL", "V");
1109    }
1110
1111    /** Verifies that enabling verbose logging does NOT set the hal log property in user builds. */
1112    @Test
1113    public void enablingVerboseLoggingDoeNotSetHalLogPropertyInUserBuilds() {
1114        reset(mPropertyService);  // Ignore calls made in setUp()
1115        when(mBuildProperties.isUserBuild()).thenReturn(true);
1116        when(mBuildProperties.isEngBuild()).thenReturn(false);
1117        when(mBuildProperties.isUserdebugBuild()).thenReturn(false);
1118        mWsm.enableVerboseLogging(1);
1119        verify(mPropertyService, never()).set(anyString(), anyString());
1120    }
1121
1122    private int testGetSupportedFeaturesCase(int supportedFeatures, boolean rttConfigured) {
1123        AsyncChannel channel = mock(AsyncChannel.class);
1124        Message reply = Message.obtain();
1125        reply.arg1 = supportedFeatures;
1126        reset(mPropertyService);  // Ignore calls made in setUp()
1127        when(channel.sendMessageSynchronously(WifiStateMachine.CMD_GET_SUPPORTED_FEATURES))
1128                .thenReturn(reply);
1129        when(mPropertyService.getBoolean("config.disable_rtt", false))
1130                .thenReturn(rttConfigured);
1131        return mWsm.syncGetSupportedFeatures(channel);
1132    }
1133
1134    /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */
1135    @Test
1136    public void syncGetSupportedFeatures() {
1137        final int featureAware = WifiManager.WIFI_FEATURE_AWARE;
1138        final int featureInfra = WifiManager.WIFI_FEATURE_INFRA;
1139        final int featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT;
1140        final int featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT;
1141
1142        assertEquals(0, testGetSupportedFeaturesCase(0, false));
1143        assertEquals(0, testGetSupportedFeaturesCase(0, true));
1144        assertEquals(featureAware | featureInfra,
1145                testGetSupportedFeaturesCase(featureAware | featureInfra, false));
1146        assertEquals(featureAware | featureInfra,
1147                testGetSupportedFeaturesCase(featureAware | featureInfra, true));
1148        assertEquals(featureInfra | featureD2dRtt,
1149                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, false));
1150        assertEquals(featureInfra,
1151                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, true));
1152        assertEquals(featureInfra | featureD2apRtt,
1153                testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, false));
1154        assertEquals(featureInfra,
1155                testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, true));
1156        assertEquals(featureInfra | featureD2dRtt | featureD2apRtt,
1157                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, false));
1158        assertEquals(featureInfra,
1159                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, true));
1160    }
1161
1162    /**
1163     * Verify that syncAddOrUpdatePasspointConfig will redirect calls to {@link PasspointManager}
1164     * and returning the result that's returned from {@link PasspointManager}.
1165     */
1166    @Test
1167    public void syncAddOrUpdatePasspointConfig() throws Exception {
1168        when(mPasspointManager.addOrUpdateProvider(any(PasspointConfiguration.class)))
1169                .thenReturn(true);
1170        mLooper.startAutoDispatch();
1171        assertTrue(mWsm.syncAddOrUpdatePasspointConfig(mWsmAsyncChannel,
1172                new PasspointConfiguration()));
1173        mLooper.stopAutoDispatch();
1174        reset(mPasspointManager);
1175
1176        when(mPasspointManager.addOrUpdateProvider(any(PasspointConfiguration.class)))
1177                .thenReturn(false);
1178        mLooper.startAutoDispatch();
1179        assertFalse(mWsm.syncAddOrUpdatePasspointConfig(mWsmAsyncChannel,
1180                new PasspointConfiguration()));
1181        mLooper.stopAutoDispatch();
1182    }
1183
1184    /**
1185     * Verify that syncRemovePasspointConfig will redirect calls to {@link PasspointManager}
1186     * and returning the result that's returned from {@link PasspointManager}.
1187     */
1188    @Test
1189    public void syncRemovePasspointConfig() throws Exception {
1190        String fqdn = "test.com";
1191        when(mPasspointManager.removeProvider(fqdn)).thenReturn(true);
1192        mLooper.startAutoDispatch();
1193        assertTrue(mWsm.syncRemovePasspointConfig(mWsmAsyncChannel, fqdn));
1194        mLooper.stopAutoDispatch();
1195        reset(mPasspointManager);
1196
1197        when(mPasspointManager.removeProvider(fqdn)).thenReturn(false);
1198        mLooper.startAutoDispatch();
1199        assertFalse(mWsm.syncRemovePasspointConfig(mWsmAsyncChannel, fqdn));
1200        mLooper.stopAutoDispatch();
1201    }
1202
1203    /**
1204     * Verify that syncRemovePasspointConfig will redirect calls to {@link PasspointManager}
1205     * and returning the result that's returned from {@link PasspointManager} when in client mode.
1206     */
1207    @Test
1208    public void syncRemovePasspointConfigInClientMode() throws Exception {
1209        loadComponentsInStaMode();
1210        syncRemovePasspointConfig();
1211    }
1212
1213    /**
1214     * Verify that syncGetPasspointConfigs will redirect calls to {@link PasspointManager}
1215     * and returning the result that's returned from {@link PasspointManager}.
1216     */
1217    @Test
1218    public void syncGetPasspointConfigs() throws Exception {
1219        // Setup expected configs.
1220        List<PasspointConfiguration> expectedConfigs = new ArrayList<>();
1221        PasspointConfiguration config = new PasspointConfiguration();
1222        HomeSp homeSp = new HomeSp();
1223        homeSp.setFqdn("test.com");
1224        config.setHomeSp(homeSp);
1225        expectedConfigs.add(config);
1226
1227        when(mPasspointManager.getProviderConfigs()).thenReturn(expectedConfigs);
1228        mLooper.startAutoDispatch();
1229        assertEquals(expectedConfigs, mWsm.syncGetPasspointConfigs(mWsmAsyncChannel));
1230        mLooper.stopAutoDispatch();
1231        reset(mPasspointManager);
1232
1233        when(mPasspointManager.getProviderConfigs())
1234                .thenReturn(new ArrayList<PasspointConfiguration>());
1235        mLooper.startAutoDispatch();
1236        assertTrue(mWsm.syncGetPasspointConfigs(mWsmAsyncChannel).isEmpty());
1237        mLooper.stopAutoDispatch();
1238    }
1239
1240    /**
1241     * Verify that syncGetMatchingWifiConfig will redirect calls to {@link PasspointManager}
1242     * with expected {@link WifiConfiguration} being returned when in client mode.
1243     *
1244     * @throws Exception
1245     */
1246    @Test
1247    public void syncGetMatchingWifiConfigInClientMode() throws Exception {
1248        loadComponentsInStaMode();
1249
1250        when(mPasspointManager.getMatchingWifiConfig(any(ScanResult.class))).thenReturn(null);
1251        mLooper.startAutoDispatch();
1252        assertNull(mWsm.syncGetMatchingWifiConfig(new ScanResult(), mWsmAsyncChannel));
1253        mLooper.stopAutoDispatch();
1254        reset(mPasspointManager);
1255
1256        WifiConfiguration expectedConfig = new WifiConfiguration();
1257        expectedConfig.SSID = "TestSSID";
1258        when(mPasspointManager.getMatchingWifiConfig(any(ScanResult.class)))
1259                .thenReturn(expectedConfig);
1260        mLooper.startAutoDispatch();
1261        WifiConfiguration actualConfig = mWsm.syncGetMatchingWifiConfig(new ScanResult(),
1262                mWsmAsyncChannel);
1263        mLooper.stopAutoDispatch();
1264        assertEquals(expectedConfig.SSID, actualConfig.SSID);
1265    }
1266
1267    /**
1268     * Verify that syncGetMatchingWifiConfig will be a no-op and return {@code null} when not in
1269     * client mode.
1270     *
1271     * @throws Exception
1272     */
1273    @Test
1274    public void syncGetMatchingWifiConfigInNonClientMode() throws Exception {
1275        mLooper.startAutoDispatch();
1276        assertNull(mWsm.syncGetMatchingWifiConfig(new ScanResult(), mWsmAsyncChannel));
1277        mLooper.stopAutoDispatch();
1278        verify(mPasspointManager, never()).getMatchingWifiConfig(any(ScanResult.class));
1279    }
1280
1281    /**
1282     * Verify successful Wps PBC network connection.
1283     */
1284    @Test
1285    public void wpsPbcConnectSuccess() throws Exception {
1286        loadComponentsInStaMode();
1287        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1288        mLooper.dispatchAll();
1289
1290        when(mWifiNative.startWpsPbc(eq(sBSSID))).thenReturn(true);
1291        WpsInfo wpsInfo = new WpsInfo();
1292        wpsInfo.setup = WpsInfo.PBC;
1293        wpsInfo.BSSID = sBSSID;
1294
1295        mLooper.startAutoDispatch();
1296        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1297        mLooper.stopAutoDispatch();
1298        verify(mWifiNative).startWpsPbc(eq(sBSSID));
1299
1300        assertEquals("WpsRunningState", getCurrentState().getName());
1301
1302        setupMocksForWpsNetworkMigration();
1303
1304        mLooper.startAutoDispatch();
1305        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1306        mLooper.stopAutoDispatch();
1307
1308        assertEquals("DisconnectedState", getCurrentState().getName());
1309    }
1310
1311    /**
1312     * Verify failure in starting Wps PBC network connection.
1313     */
1314    @Test
1315    public void wpsPbcConnectFailure() throws Exception {
1316        loadComponentsInStaMode();
1317        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1318        mLooper.dispatchAll();
1319
1320        when(mWifiNative.startWpsPbc(eq(sBSSID))).thenReturn(false);
1321        WpsInfo wpsInfo = new WpsInfo();
1322        wpsInfo.setup = WpsInfo.PBC;
1323        wpsInfo.BSSID = sBSSID;
1324
1325        mLooper.startAutoDispatch();
1326        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1327        mLooper.stopAutoDispatch();
1328        verify(mWifiNative).startWpsPbc(eq(sBSSID));
1329
1330        assertFalse("WpsRunningState".equals(getCurrentState().getName()));
1331    }
1332
1333    /**
1334     * Verify successful Wps Pin Display network connection.
1335     */
1336    @Test
1337    public void wpsPinDisplayConnectSuccess() throws Exception {
1338        loadComponentsInStaMode();
1339        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1340        mLooper.dispatchAll();
1341
1342        when(mWifiNative.startWpsPinDisplay(eq(sBSSID))).thenReturn("34545434");
1343        WpsInfo wpsInfo = new WpsInfo();
1344        wpsInfo.setup = WpsInfo.DISPLAY;
1345        wpsInfo.BSSID = sBSSID;
1346
1347        mLooper.startAutoDispatch();
1348        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1349        mLooper.stopAutoDispatch();
1350        verify(mWifiNative).startWpsPinDisplay(eq(sBSSID));
1351
1352        assertEquals("WpsRunningState", getCurrentState().getName());
1353
1354        setupMocksForWpsNetworkMigration();
1355
1356        mLooper.startAutoDispatch();
1357        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1358        mLooper.stopAutoDispatch();
1359
1360        assertEquals("DisconnectedState", getCurrentState().getName());
1361    }
1362
1363    /**
1364     * Verify failure in Wps Pin Display network connection.
1365     */
1366    @Test
1367    public void wpsPinDisplayConnectFailure() throws Exception {
1368        loadComponentsInStaMode();
1369        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1370        mLooper.dispatchAll();
1371
1372        when(mWifiNative.startWpsPinDisplay(eq(sBSSID))).thenReturn(null);
1373        WpsInfo wpsInfo = new WpsInfo();
1374        wpsInfo.setup = WpsInfo.DISPLAY;
1375        wpsInfo.BSSID = sBSSID;
1376
1377        mLooper.startAutoDispatch();
1378        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1379        mLooper.stopAutoDispatch();
1380        verify(mWifiNative).startWpsPinDisplay(eq(sBSSID));
1381
1382        assertFalse("WpsRunningState".equals(getCurrentState().getName()));
1383    }
1384
1385    @Test
1386    public void handleVendorHalDeath() throws Exception {
1387        ArgumentCaptor<WifiNative.VendorHalDeathEventHandler> deathHandlerCapturer =
1388                ArgumentCaptor.forClass(WifiNative.VendorHalDeathEventHandler.class);
1389        when(mWifiNative.initializeVendorHal(deathHandlerCapturer.capture())).thenReturn(true);
1390
1391        // Trigger initialize to capture the death handler registration.
1392        mLooper.startAutoDispatch();
1393        assertTrue(mWsm.syncInitialize(mWsmAsyncChannel));
1394        mLooper.stopAutoDispatch();
1395
1396        verify(mWifiNative).initializeVendorHal(any(WifiNative.VendorHalDeathEventHandler.class));
1397        WifiNative.VendorHalDeathEventHandler deathHandler = deathHandlerCapturer.getValue();
1398
1399        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1400        mLooper.dispatchAll();
1401
1402        // We should not be in initial state now.
1403        assertFalse("InitialState".equals(getCurrentState().getName()));
1404
1405        // Now trigger the death notification.
1406        mLooper.startAutoDispatch();
1407        deathHandler.onDeath();
1408        mLooper.stopAutoDispatch();
1409
1410        // We should back to initial state after vendor HAL death.
1411        assertTrue("InitialState".equals(getCurrentState().getName()));
1412    }
1413
1414    private void setupMocksForWpsNetworkMigration() {
1415        int newNetworkId = 5;
1416        // Now trigger the network connection event for adding the WPS network.
1417        doAnswer(new AnswerWithArguments() {
1418            public boolean answer(Map<String, WifiConfiguration> configs,
1419                                  SparseArray<Map<String, String>> networkExtras) throws Exception {
1420                configs.put("dummy", new WifiConfiguration());
1421                return true;
1422            }
1423        }).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
1424        when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
1425                .thenReturn(new NetworkUpdateResult(newNetworkId));
1426        when(mWifiConfigManager.enableNetwork(eq(newNetworkId), anyBoolean(), anyInt()))
1427                .thenReturn(true);
1428    }
1429}
1430