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