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