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