WifiStateMachineTest.java revision d27716a747d9cf2d86153aa9ec1b55b663808b28
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.assertNotEquals;
34import static org.junit.Assert.assertNotNull;
35import static org.junit.Assert.assertNull;
36import static org.junit.Assert.assertTrue;
37import static org.mockito.Mockito.*;
38
39import android.app.ActivityManager;
40import android.app.test.MockAnswerUtil.AnswerWithArguments;
41import android.app.test.TestAlarmManager;
42import android.content.Context;
43import android.content.Intent;
44import android.content.pm.PackageManager;
45import android.content.pm.UserInfo;
46import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
47import android.net.ConnectivityManager;
48import android.net.DhcpResults;
49import android.net.LinkProperties;
50import android.net.dhcp.DhcpClient;
51import android.net.ip.IpManager;
52import android.net.wifi.IApInterface;
53import android.net.wifi.IClientInterface;
54import android.net.wifi.IWificond;
55import android.net.wifi.ScanResult;
56import android.net.wifi.SupplicantState;
57import android.net.wifi.WifiConfiguration;
58import android.net.wifi.WifiInfo;
59import android.net.wifi.WifiManager;
60import android.net.wifi.WifiScanner;
61import android.net.wifi.WifiSsid;
62import android.net.wifi.WpsInfo;
63import android.net.wifi.hotspot2.PasspointConfiguration;
64import android.net.wifi.hotspot2.pps.HomeSp;
65import android.net.wifi.p2p.IWifiP2pManager;
66import android.os.BatteryStats;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Handler;
70import android.os.HandlerThread;
71import android.os.IBinder;
72import android.os.IInterface;
73import android.os.INetworkManagementService;
74import android.os.IPowerManager;
75import android.os.Looper;
76import android.os.Message;
77import android.os.Messenger;
78import android.os.PowerManager;
79import android.os.Process;
80import android.os.RemoteException;
81import android.os.UserHandle;
82import android.os.UserManager;
83import android.os.test.TestLooper;
84import android.provider.Settings;
85import android.security.KeyStore;
86import android.telephony.PhoneStateListener;
87import android.telephony.TelephonyManager;
88import android.test.mock.MockContentProvider;
89import android.test.mock.MockContentResolver;
90import android.test.suitebuilder.annotation.SmallTest;
91import android.util.Log;
92import android.util.Pair;
93import android.util.SparseArray;
94
95import com.android.internal.R;
96import com.android.internal.app.IBatteryStats;
97import com.android.internal.util.AsyncChannel;
98import com.android.internal.util.IState;
99import com.android.internal.util.StateMachine;
100import com.android.server.wifi.hotspot2.NetworkDetail;
101import com.android.server.wifi.hotspot2.PasspointManager;
102import com.android.server.wifi.p2p.WifiP2pServiceImpl;
103import com.android.server.wifi.util.WifiPermissionsUtil;
104
105import org.junit.After;
106import org.junit.Before;
107import org.junit.Test;
108import org.mockito.ArgumentCaptor;
109import org.mockito.ArgumentMatcher;
110import org.mockito.InOrder;
111import org.mockito.Mock;
112import org.mockito.MockitoAnnotations;
113
114import java.io.ByteArrayOutputStream;
115import java.io.PrintWriter;
116import java.lang.reflect.Field;
117import java.lang.reflect.InvocationTargetException;
118import java.lang.reflect.Method;
119import java.util.ArrayList;
120import java.util.Arrays;
121import java.util.HashSet;
122import java.util.List;
123import java.util.Map;
124import java.util.Set;
125import java.util.concurrent.CountDownLatch;
126
127/**
128 * Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
129 */
130@SmallTest
131public class WifiStateMachineTest {
132    public static final String TAG = "WifiStateMachineTest";
133
134    private static final int MANAGED_PROFILE_UID = 1100000;
135    private static final int OTHER_USER_UID = 1200000;
136    private static final int LOG_REC_LIMIT_IN_VERBOSE_MODE =
137            (ActivityManager.isLowRamDeviceStatic()
138                    ? WifiStateMachine.NUM_LOG_RECS_VERBOSE_LOW_MEMORY
139                    : WifiStateMachine.NUM_LOG_RECS_VERBOSE);
140    private static final int WPS_SUPPLICANT_NETWORK_ID = 5;
141    private static final int WPS_FRAMEWORK_NETWORK_ID = 10;
142    private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
143    private static final String OP_PACKAGE_NAME = "com.xxx";
144
145    private long mBinderToken;
146
147    private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) {
148        return mock(class1, withSettings().extraInterfaces(interfaces));
149    }
150
151    private static <T, I> IBinder mockService(Class<T> class1, Class<I> iface) {
152        T tImpl = mockWithInterfaces(class1, iface);
153        IBinder binder = mock(IBinder.class);
154        when(((IInterface) tImpl).asBinder()).thenReturn(binder);
155        when(binder.queryLocalInterface(iface.getCanonicalName()))
156                .thenReturn((IInterface) tImpl);
157        return binder;
158    }
159
160    private void enableDebugLogs() {
161        mWsm.enableVerboseLogging(1);
162    }
163
164    private FrameworkFacade getFrameworkFacade() throws Exception {
165        FrameworkFacade facade = mock(FrameworkFacade.class);
166
167        when(facade.getService(Context.NETWORKMANAGEMENT_SERVICE)).thenReturn(
168                mockWithInterfaces(IBinder.class, INetworkManagementService.class));
169
170        IBinder p2pBinder = mockService(WifiP2pServiceImpl.class, IWifiP2pManager.class);
171        when(facade.getService(Context.WIFI_P2P_SERVICE)).thenReturn(p2pBinder);
172
173        WifiP2pServiceImpl p2pm = (WifiP2pServiceImpl) p2pBinder.queryLocalInterface(
174                IWifiP2pManager.class.getCanonicalName());
175
176        final CountDownLatch untilDone = new CountDownLatch(1);
177        mP2pThread = new HandlerThread("WifiP2pMockThread") {
178            @Override
179            protected void onLooperPrepared() {
180                untilDone.countDown();
181            }
182        };
183
184        mP2pThread.start();
185        untilDone.await();
186
187        Handler handler = new Handler(mP2pThread.getLooper());
188        when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler));
189
190        IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
191        when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
192
193        when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class)))
194                .then(new AnswerWithArguments() {
195                    public IpManager answer(
196                            Context context, String ifname, IpManager.Callback callback) {
197                        mIpManagerCallback = callback;
198                        return mIpManager;
199                    }
200                });
201
202        return facade;
203    }
204
205    private Context getContext() throws Exception {
206        PackageManager pkgMgr = mock(PackageManager.class);
207        when(pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
208
209        Context context = mock(Context.class);
210        when(context.getPackageManager()).thenReturn(pkgMgr);
211
212        MockContentResolver mockContentResolver = new MockContentResolver();
213        mockContentResolver.addProvider(Settings.AUTHORITY,
214                new MockContentProvider(context) {
215                    @Override
216                    public Bundle call(String method, String arg, Bundle extras) {
217                        return new Bundle();
218                    }
219                });
220        when(context.getContentResolver()).thenReturn(mockContentResolver);
221
222        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(
223                new PowerManager(context, mock(IPowerManager.class), new Handler()));
224
225        mAlarmManager = new TestAlarmManager();
226        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
227                mAlarmManager.getAlarmManager());
228
229        when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
230                mock(ConnectivityManager.class));
231
232        when(context.getOpPackageName()).thenReturn(OP_PACKAGE_NAME);
233
234        return context;
235    }
236
237    private MockResources getMockResources() {
238        MockResources resources = new MockResources();
239        resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false);
240        resources.setBoolean(
241                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, false);
242        return resources;
243    }
244
245    private IState getCurrentState() throws
246            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
247        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
248        method.setAccessible(true);
249        return (IState) method.invoke(mWsm);
250    }
251
252    private static HandlerThread getWsmHandlerThread(WifiStateMachine wsm) throws
253            NoSuchFieldException, InvocationTargetException, IllegalAccessException {
254        Field field = StateMachine.class.getDeclaredField("mSmThread");
255        field.setAccessible(true);
256        return (HandlerThread) field.get(wsm);
257    }
258
259    private static void stopLooper(final Looper looper) throws Exception {
260        new Handler(looper).post(new Runnable() {
261            @Override
262            public void run() {
263                looper.quitSafely();
264            }
265        });
266    }
267
268    private void dumpState() {
269        ByteArrayOutputStream stream = new ByteArrayOutputStream();
270        PrintWriter writer = new PrintWriter(stream);
271        mWsm.dump(null, writer, null);
272        writer.flush();
273        Log.d(TAG, "WifiStateMachine state -" + stream.toString());
274    }
275
276    private static ScanDetail getGoogleGuestScanDetail(int rssi) {
277        ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
278        ie[0] = ScanResults.generateSsidIe(sSSID);
279        NetworkDetail nd = new NetworkDetail(sBSSID, ie, new ArrayList<String>(), sFreq);
280        ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq,
281                Long.MAX_VALUE, /* needed so that scan results aren't rejected because
282                                   there older than scan start */
283                ie, new ArrayList<String>());
284        return detail;
285    }
286
287    private ArrayList<ScanDetail> getMockScanResults() {
288        ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
289        ArrayList<ScanDetail> list = sr.getScanDetailArrayList();
290
291        int rssi = -65;
292        list.add(getGoogleGuestScanDetail(rssi));
293        return list;
294    }
295
296    private void injectDhcpSuccess(DhcpResults dhcpResults) {
297        mIpManagerCallback.onNewDhcpResults(dhcpResults);
298        mIpManagerCallback.onProvisioningSuccess(new LinkProperties());
299    }
300
301    private void injectDhcpFailure() {
302        mIpManagerCallback.onNewDhcpResults(null);
303        mIpManagerCallback.onProvisioningFailure(new LinkProperties());
304    }
305
306    static final String   sSSID = "\"GoogleGuest\"";
307    static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
308    static final String   sBSSID = "01:02:03:04:05:06";
309    static final int      sFreq = 2437;
310    static final String   WIFI_IFACE_NAME = "mockWlan";
311
312    WifiStateMachine mWsm;
313    HandlerThread mWsmThread;
314    HandlerThread mP2pThread;
315    HandlerThread mSyncThread;
316    AsyncChannel  mWsmAsyncChannel;
317    TestAlarmManager mAlarmManager;
318    MockWifiMonitor mWifiMonitor;
319    TestLooper mLooper;
320    Context mContext;
321    MockResources mResources;
322    FrameworkFacade mFrameworkFacade;
323    IpManager.Callback mIpManagerCallback;
324    PhoneStateListener mPhoneStateListener;
325
326    final ArgumentCaptor<SoftApManager.Listener> mSoftApManagerListenerCaptor =
327                    ArgumentCaptor.forClass(SoftApManager.Listener.class);
328
329    @Mock WifiScanner mWifiScanner;
330    @Mock SupplicantStateTracker mSupplicantStateTracker;
331    @Mock WifiMetrics mWifiMetrics;
332    @Mock UserManager mUserManager;
333    @Mock WifiApConfigStore mApConfigStore;
334    @Mock BackupManagerProxy mBackupManagerProxy;
335    @Mock WifiCountryCode mCountryCode;
336    @Mock WifiInjector mWifiInjector;
337    @Mock WifiLastResortWatchdog mWifiLastResortWatchdog;
338    @Mock PropertyService mPropertyService;
339    @Mock BuildProperties mBuildProperties;
340    @Mock IWificond mWificond;
341    @Mock IApInterface mApInterface;
342    @Mock IClientInterface mClientInterface;
343    @Mock IBinder mApInterfaceBinder;
344    @Mock IBinder mClientInterfaceBinder;
345    @Mock IBinder mPackageManagerBinder;
346    @Mock WifiConfigManager mWifiConfigManager;
347    @Mock WifiNative mWifiNative;
348    @Mock WifiConnectivityManager mWifiConnectivityManager;
349    @Mock SoftApManager mSoftApManager;
350    @Mock WifiStateTracker mWifiStateTracker;
351    @Mock PasspointManager mPasspointManager;
352    @Mock SelfRecovery mSelfRecovery;
353    @Mock WifiPermissionsUtil mWifiPermissionsUtil;
354    @Mock IpManager mIpManager;
355    @Mock TelephonyManager mTelephonyManager;
356    @Mock WrongPasswordNotifier mWrongPasswordNotifier;
357    @Mock Clock mClock;
358
359    public WifiStateMachineTest() throws Exception {
360    }
361
362    @Before
363    public void setUp() throws Exception {
364        Log.d(TAG, "Setting up ...");
365
366        // Ensure looper exists
367        mLooper = new TestLooper();
368
369        MockitoAnnotations.initMocks(this);
370
371        /** uncomment this to enable logs from WifiStateMachines */
372        // enableDebugLogs();
373
374        mWifiMonitor = new MockWifiMonitor();
375        when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
376        when(mWifiInjector.getClock()).thenReturn(new Clock());
377        when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog);
378        when(mWifiInjector.getPropertyService()).thenReturn(mPropertyService);
379        when(mWifiInjector.getBuildProperties()).thenReturn(mBuildProperties);
380        when(mWifiInjector.getKeyStore()).thenReturn(mock(KeyStore.class));
381        when(mWifiInjector.getWifiBackupRestore()).thenReturn(mock(WifiBackupRestore.class));
382        when(mWifiInjector.makeWifiDiagnostics(anyObject())).thenReturn(
383                mock(BaseWifiDiagnostics.class));
384        when(mWifiInjector.makeWificond()).thenReturn(mWificond);
385        when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager);
386        when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
387        when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
388                .thenReturn(mWifiConnectivityManager);
389        when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
390                mSoftApManagerListenerCaptor.capture(), any(IApInterface.class),
391                any(WifiConfiguration.class)))
392                .thenReturn(mSoftApManager);
393        when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
394        when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
395        when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor);
396        when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
397        when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery);
398        when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
399        when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager);
400        when(mWifiInjector.getClock()).thenReturn(mClock);
401
402        when(mWifiNative.setupForClientMode())
403                .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface));
404        when(mWifiNative.setupForSoftApMode())
405                .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
406        when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
407        when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
408        when(mWifiNative.enableSupplicant()).thenReturn(true);
409        when(mWifiNative.disableSupplicant()).thenReturn(true);
410        when(mWifiNative.getFrameworkNetworkId(anyInt())).thenReturn(0);
411
412
413        mFrameworkFacade = getFrameworkFacade();
414        mContext = getContext();
415
416        mResources = getMockResources();
417        when(mContext.getResources()).thenReturn(mResources);
418
419        when(mFrameworkFacade.getIntegerSetting(mContext,
420                Settings.Global.WIFI_FREQUENCY_BAND,
421                WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn(
422                WifiManager.WIFI_FREQUENCY_BAND_AUTO);
423
424        when(mFrameworkFacade.makeApConfigStore(eq(mContext), eq(mBackupManagerProxy)))
425                .thenReturn(mApConfigStore);
426
427        when(mFrameworkFacade.makeSupplicantStateTracker(
428                any(Context.class), any(WifiConfigManager.class),
429                any(Handler.class))).thenReturn(mSupplicantStateTracker);
430
431        when(mUserManager.getProfileParent(11))
432                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0));
433        when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList(
434                new UserInfo(UserHandle.USER_SYSTEM, "owner", 0),
435                new UserInfo(11, "managed profile", 0)));
436
437        when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
438        when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder);
439
440        doAnswer(new AnswerWithArguments() {
441            public void answer(PhoneStateListener phoneStateListener, int events)
442                    throws Exception {
443                mPhoneStateListener = phoneStateListener;
444            }
445        }).when(mTelephonyManager).listen(any(PhoneStateListener.class), anyInt());
446
447        initializeWsm();
448    }
449
450    private void initializeWsm() throws Exception {
451        mWsm = new WifiStateMachine(mContext, mFrameworkFacade, mLooper.getLooper(),
452                mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode, mWifiNative,
453                mWrongPasswordNotifier);
454        mWsmThread = getWsmHandlerThread(mWsm);
455
456        final AsyncChannel channel = new AsyncChannel();
457        Handler handler = new Handler(mLooper.getLooper()) {
458            @Override
459            public void handleMessage(Message msg) {
460                switch (msg.what) {
461                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
462                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
463                            mWsmAsyncChannel = channel;
464                        } else {
465                            Log.d(TAG, "Failed to connect Command channel " + this);
466                        }
467                        break;
468                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
469                        Log.d(TAG, "Command channel disconnected" + this);
470                        break;
471                }
472            }
473        };
474
475        channel.connect(mContext, handler, mWsm.getMessenger());
476        mLooper.dispatchAll();
477        /* Now channel is supposed to be connected */
478
479        mBinderToken = Binder.clearCallingIdentity();
480
481        /* Send the BOOT_COMPLETED message to setup some WSM state. */
482        mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
483        mLooper.dispatchAll();
484    }
485
486    @After
487    public void cleanUp() throws Exception {
488        Binder.restoreCallingIdentity(mBinderToken);
489
490        if (mSyncThread != null) stopLooper(mSyncThread.getLooper());
491        if (mWsmThread != null) stopLooper(mWsmThread.getLooper());
492        if (mP2pThread != null) stopLooper(mP2pThread.getLooper());
493
494        mWsmThread = null;
495        mP2pThread = null;
496        mSyncThread = null;
497        mWsmAsyncChannel = null;
498        mWsm = null;
499    }
500
501    @Test
502    public void createNew() throws Exception {
503        assertEquals("InitialState", getCurrentState().getName());
504
505        mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
506        mLooper.dispatchAll();
507        assertEquals("InitialState", getCurrentState().getName());
508    }
509
510    @Test
511    public void loadComponentsInStaMode() throws Exception {
512        startSupplicantAndDispatchMessages();
513
514        verify(mContext).sendStickyBroadcastAsUser(
515                (Intent) argThat(new WifiEnablingStateIntentMatcher()), eq(UserHandle.ALL));
516
517        assertEquals("DisconnectedState", getCurrentState().getName());
518    }
519
520    private void checkApStateChangedBroadcast(Intent intent, int expectedCurrentState,
521            int expectedPrevState, int expectedErrorCode, String expectedIfaceName,
522            int expectedMode) {
523        int currentState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
524        int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
525        int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON, HOTSPOT_NO_ERROR);
526        String ifaceName = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
527        int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
528        assertEquals(expectedCurrentState, currentState);
529        assertEquals(expectedPrevState, prevState);
530        assertEquals(expectedErrorCode, errorCode);
531        assertEquals(expectedIfaceName, ifaceName);
532        assertEquals(expectedMode, mode);
533    }
534
535    private void loadComponentsInApMode(int mode) throws Exception {
536        SoftApModeConfiguration config = new SoftApModeConfiguration(mode, new WifiConfiguration());
537        mWsm.setHostApRunning(config, true);
538        mLooper.dispatchAll();
539
540        assertEquals("SoftApState", getCurrentState().getName());
541
542        verify(mWifiNative).setupForSoftApMode();
543        verify(mSoftApManager).start();
544
545        // reset expectations for mContext due to previously sent AP broadcast
546        reset(mContext);
547
548        // get the SoftApManager.Listener and trigger some updates
549        SoftApManager.Listener listener = mSoftApManagerListenerCaptor.getValue();
550        listener.onStateChanged(WIFI_AP_STATE_ENABLING, 0);
551        listener.onStateChanged(WIFI_AP_STATE_ENABLED, 0);
552        listener.onStateChanged(WIFI_AP_STATE_DISABLING, 0);
553        // note, this will trigger a mode change when TestLooper is dispatched
554        listener.onStateChanged(WIFI_AP_STATE_DISABLED, 0);
555
556        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
557        verify(mContext, times(4))
558                .sendStickyBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL));
559
560        List<Intent> capturedIntents = intentCaptor.getAllValues();
561        checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
562                WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
563        checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_ENABLED,
564                WIFI_AP_STATE_ENABLING, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
565        checkApStateChangedBroadcast(capturedIntents.get(2), WIFI_AP_STATE_DISABLING,
566                WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
567        checkApStateChangedBroadcast(capturedIntents.get(3), WIFI_AP_STATE_DISABLED,
568                WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
569    }
570
571    @Test
572    public void loadComponentsInApModeForTethering() throws Exception {
573        loadComponentsInApMode(WifiManager.IFACE_IP_MODE_TETHERED);
574    }
575
576    @Test
577    public void loadComponentsInApModeForLOHS() throws Exception {
578        loadComponentsInApMode(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
579    }
580
581    @Test
582    public void shouldRequireSupplicantStartupToLeaveInitialState() throws Exception {
583        when(mWifiNative.enableSupplicant()).thenReturn(false);
584        mWsm.setSupplicantRunning(true);
585        mLooper.dispatchAll();
586        assertEquals("InitialState", getCurrentState().getName());
587        // we should not be sending a wifi enabling update
588        verify(mContext, never()).sendStickyBroadcastAsUser(
589                (Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
590    }
591
592    @Test
593    public void shouldRequireWificondToLeaveInitialState() throws Exception {
594        // We start out with valid default values, break them going backwards so that
595        // we test all the bailout cases.
596
597        // ClientInterface dies after creation.
598        doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt());
599        mWsm.setSupplicantRunning(true);
600        mLooper.dispatchAll();
601        assertEquals("InitialState", getCurrentState().getName());
602
603        // Failed to even create the client interface.
604        when(mWificond.createClientInterface()).thenReturn(null);
605        mWsm.setSupplicantRunning(true);
606        mLooper.dispatchAll();
607        assertEquals("InitialState", getCurrentState().getName());
608
609        // Failed to get wificond proxy.
610        when(mWifiInjector.makeWificond()).thenReturn(null);
611        mWsm.setSupplicantRunning(true);
612        mLooper.dispatchAll();
613        assertEquals("InitialState", getCurrentState().getName());
614    }
615
616    @Test
617    public void loadComponentsFailure() throws Exception {
618        when(mWifiNative.enableSupplicant()).thenReturn(false);
619
620        mWsm.setSupplicantRunning(true);
621        mLooper.dispatchAll();
622        assertEquals("InitialState", getCurrentState().getName());
623
624        mWsm.setSupplicantRunning(true);
625        mLooper.dispatchAll();
626        assertEquals("InitialState", getCurrentState().getName());
627    }
628
629    @Test
630    public void checkInitialStateStickyWhenDisabledMode() throws Exception {
631        mLooper.dispatchAll();
632        assertEquals("InitialState", getCurrentState().getName());
633        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
634
635        mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE);
636        mLooper.dispatchAll();
637        assertEquals(WifiStateMachine.DISABLED_MODE, mWsm.getOperationalModeForTest());
638        assertEquals("InitialState", getCurrentState().getName());
639    }
640
641    @Test
642    public void shouldStartSupplicantWhenConnectModeRequested() throws Exception {
643        // The first time we start out in InitialState, we sit around here.
644        mLooper.dispatchAll();
645        assertEquals("InitialState", getCurrentState().getName());
646        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
647
648        // But if someone tells us to enter connect mode, we start up supplicant
649        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
650        mLooper.dispatchAll();
651        assertEquals("SupplicantStartingState", getCurrentState().getName());
652    }
653
654    /**
655     *  Test that mode changes accurately reflect the value for isWifiEnabled.
656     */
657    @Test
658    public void checkIsWifiEnabledForModeChanges() throws Exception {
659        // Check initial state
660        mLooper.dispatchAll();
661        assertEquals("InitialState", getCurrentState().getName());
662        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
663
664        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
665        startSupplicantAndDispatchMessages();
666        mWsm.setSupplicantRunning(true);
667        mLooper.dispatchAll();
668        assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
669        assertEquals("ScanModeState", getCurrentState().getName());
670        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
671        verify(mContext, never()).sendStickyBroadcastAsUser(
672                (Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
673
674
675        // switch to connect mode and verify wifi is reported as enabled
676        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
677        mLooper.dispatchAll();
678        assertEquals("DisconnectedState", getCurrentState().getName());
679        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
680        assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
681        verify(mContext).sendStickyBroadcastAsUser(
682                (Intent) argThat(new WifiEnablingStateIntentMatcher()), eq(UserHandle.ALL));
683
684        // reset the expectations on mContext since we did get an expected broadcast, but we should
685        // not on the next transition
686        reset(mContext);
687
688        // now go back to scan mode with "wifi disabled" to verify the reported wifi state.
689        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
690        mLooper.dispatchAll();
691        assertEquals(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE,
692                     mWsm.getOperationalModeForTest());
693        assertEquals("ScanModeState", getCurrentState().getName());
694        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
695        verify(mContext, never()).sendStickyBroadcastAsUser(
696                (Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
697
698        // now go to AP mode
699        mWsm.setSupplicantRunning(false);
700        mWsm.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
701        mWsm.sendMessage(WifiMonitor.SUP_DISCONNECTION_EVENT);
702        SoftApModeConfiguration config = new SoftApModeConfiguration(
703                WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
704        mWsm.setHostApRunning(config, true);
705        mLooper.dispatchAll();
706        assertEquals("SoftApState", getCurrentState().getName());
707        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
708        verify(mContext, never()).sendStickyBroadcastAsUser(
709                (Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
710    }
711
712    private class WifiEnablingStateIntentMatcher implements ArgumentMatcher<Intent> {
713        @Override
714        public boolean matches(Intent intent) {
715            if (WifiManager.WIFI_STATE_CHANGED_ACTION != intent.getAction()) {
716                // not the correct type
717                return false;
718            }
719            return WifiManager.WIFI_STATE_ENABLING
720                    == intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
721                                          WifiManager.WIFI_STATE_DISABLED);
722        }
723    }
724
725    /**
726     * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant
727     * is started.
728     */
729    @Test
730    public void checkStartInCorrectStateAfterChangingInitialState() throws Exception {
731        // Check initial state
732        mLooper.dispatchAll();
733        assertEquals("InitialState", getCurrentState().getName());
734        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
735
736        // Update the mode
737        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
738        mLooper.dispatchAll();
739        assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
740
741        // Start supplicant so we move to the next state
742        startSupplicantAndDispatchMessages();
743
744        assertEquals("ScanModeState", getCurrentState().getName());
745        verify(mContext, never()).sendStickyBroadcastAsUser(
746                (Intent) argThat(new WifiEnablingStateIntentMatcher()), any());
747    }
748
749    /**
750     * Verifies that configs can be removed when in client mode.
751     */
752    @Test
753    public void canRemoveNetworkConfigInClientMode() throws Exception {
754        boolean result;
755        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
756        initializeAndAddNetworkAndVerifySuccess();
757        mLooper.startAutoDispatch();
758        result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
759        mLooper.stopAutoDispatch();
760        assertTrue(result);
761    }
762
763    /**
764     * Verifies that configs can be removed when not in client mode.
765     */
766    @Test
767    public void canRemoveNetworkConfigWhenWifiDisabled() {
768        boolean result;
769        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
770        mLooper.startAutoDispatch();
771        result = mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0);
772        mLooper.stopAutoDispatch();
773
774        assertTrue(result);
775        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
776    }
777
778    /**
779     * Verifies that configs can be forgotten when in client mode.
780     */
781    @Test
782    public void canForgetNetworkConfigInClientMode() throws Exception {
783        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
784        initializeAndAddNetworkAndVerifySuccess();
785        mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
786        mLooper.dispatchAll();
787        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
788    }
789
790    /**
791     * Verifies that configs can be removed when not in client mode.
792     */
793    @Test
794    public void canForgetNetworkConfigWhenWifiDisabled() throws Exception {
795        when(mWifiConfigManager.removeNetwork(eq(0), anyInt())).thenReturn(true);
796        mWsm.sendMessage(WifiManager.FORGET_NETWORK, 0, MANAGED_PROFILE_UID);
797        mLooper.dispatchAll();
798        verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt());
799    }
800
801    /**
802     * Helper method to move through SupplicantStarting and SupplicantStarted states.
803     */
804    private void startSupplicantAndDispatchMessages() throws Exception {
805        mWsm.setSupplicantRunning(true);
806        mLooper.dispatchAll();
807
808        assertEquals("SupplicantStartingState", getCurrentState().getName());
809
810        when(mWifiNative.setDeviceName(anyString())).thenReturn(true);
811        when(mWifiNative.setManufacturer(anyString())).thenReturn(true);
812        when(mWifiNative.setModelName(anyString())).thenReturn(true);
813        when(mWifiNative.setModelNumber(anyString())).thenReturn(true);
814        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
815        when(mWifiNative.setConfigMethods(anyString())).thenReturn(true);
816        when(mWifiNative.setDeviceType(anyString())).thenReturn(true);
817        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
818        when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true);
819
820        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
821        mLooper.dispatchAll();
822
823        verify(mWifiNative).setupForClientMode();
824        verify(mWifiLastResortWatchdog).clearAllFailureCounts();
825    }
826
827    private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception {
828        WifiConfiguration config = new WifiConfiguration();
829        config.SSID = sSSID;
830        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
831        config.hiddenSSID = isHidden;
832
833        when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
834                .thenReturn(new NetworkUpdateResult(0));
835        when(mWifiConfigManager.getSavedNetworks()).thenReturn(Arrays.asList(config));
836        when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config);
837        when(mWifiConfigManager.getConfiguredNetworkWithPassword(0)).thenReturn(config);
838
839        mLooper.startAutoDispatch();
840        mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
841        mLooper.stopAutoDispatch();
842
843        verify(mWifiConfigManager).addOrUpdateNetwork(eq(config), anyInt());
844
845        mLooper.startAutoDispatch();
846        List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel);
847        mLooper.stopAutoDispatch();
848        assertEquals(1, configs.size());
849
850        WifiConfiguration config2 = configs.get(0);
851        assertEquals("\"GoogleGuest\"", config2.SSID);
852        assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE));
853    }
854
855    private void initializeAndAddNetworkAndVerifySuccess() throws Exception {
856        initializeAndAddNetworkAndVerifySuccess(false);
857    }
858
859    private void initializeAndAddNetworkAndVerifySuccess(boolean isHidden) throws Exception {
860        loadComponentsInStaMode();
861        addNetworkAndVerifySuccess(isHidden);
862    }
863
864    /**
865     * Helper method to retrieve WifiConfiguration by SSID.
866     *
867     * Returns the associated WifiConfiguration if it is found, null otherwise.
868     */
869    private WifiConfiguration getWifiConfigurationForNetwork(String ssid) {
870        mLooper.startAutoDispatch();
871        List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel);
872        mLooper.stopAutoDispatch();
873
874        for (WifiConfiguration checkConfig : configs) {
875            if (checkConfig.SSID.equals(ssid)) {
876                return checkConfig;
877            }
878        }
879        return null;
880    }
881
882    private void verifyScan(int band, int reportEvents, Set<String> hiddenNetworkSSIDSet) {
883        ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor =
884                ArgumentCaptor.forClass(WifiScanner.ScanSettings.class);
885        ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor =
886                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
887        verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture(),
888                eq(null));
889        WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue();
890        assertEquals("band", band, actualSettings.band);
891        assertEquals("reportEvents", reportEvents, actualSettings.reportEvents);
892
893        if (hiddenNetworkSSIDSet == null) {
894            hiddenNetworkSSIDSet = new HashSet<>();
895        }
896        Set<String> actualHiddenNetworkSSIDSet = new HashSet<>();
897        if (actualSettings.hiddenNetworks != null) {
898            for (int i = 0; i < actualSettings.hiddenNetworks.length; ++i) {
899                actualHiddenNetworkSSIDSet.add(actualSettings.hiddenNetworks[i].ssid);
900            }
901        }
902        assertEquals("hidden networks", hiddenNetworkSSIDSet, actualHiddenNetworkSSIDSet);
903
904        when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
905        mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
906
907        mLooper.dispatchAll();
908
909        List<ScanResult> reportedResults = mWsm.syncGetScanResultsList();
910        assertEquals(8, reportedResults.size());
911    }
912
913    @Test
914    public void scan() throws Exception {
915        initializeAndAddNetworkAndVerifySuccess();
916
917        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
918        mWsm.startScan(-1, 0, null, null);
919        mLooper.dispatchAll();
920
921        verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
922                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
923                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null);
924    }
925
926    @Test
927    public void scanWithHiddenNetwork() throws Exception {
928        initializeAndAddNetworkAndVerifySuccess(true);
929
930        Set<String> hiddenNetworkSet = new HashSet<>();
931        hiddenNetworkSet.add(sSSID);
932        List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
933        hiddenNetworkList.add(new WifiScanner.ScanSettings.HiddenNetwork(sSSID));
934        when(mWifiConfigManager.retrieveHiddenNetworkList()).thenReturn(hiddenNetworkList);
935
936        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
937        mWsm.startScan(-1, 0, null, null);
938        mLooper.dispatchAll();
939
940        verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
941                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
942                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
943                hiddenNetworkSet);
944    }
945
946    @Test
947    public void connect() throws Exception {
948        initializeAndAddNetworkAndVerifySuccess();
949        when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(true);
950        when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(true);
951
952        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
953        mLooper.dispatchAll();
954        verify(mWifiNative).removeAllNetworks();
955
956        mLooper.startAutoDispatch();
957        assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
958        mLooper.stopAutoDispatch();
959
960        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
961        verify(mWifiConnectivityManager).setUserConnectChoice(eq(0));
962
963        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
964        mLooper.dispatchAll();
965
966        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
967                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
968        mLooper.dispatchAll();
969
970        assertEquals("ObtainingIpState", getCurrentState().getName());
971
972        DhcpResults dhcpResults = new DhcpResults();
973        dhcpResults.setGateway("1.2.3.4");
974        dhcpResults.setIpAddress("192.168.1.100", 0);
975        dhcpResults.addDns("8.8.8.8");
976        dhcpResults.setLeaseDuration(3600);
977
978        injectDhcpSuccess(dhcpResults);
979        mLooper.dispatchAll();
980
981        assertEquals("ConnectedState", getCurrentState().getName());
982    }
983
984    @Test
985    public void connectWithNoEnablePermission() throws Exception {
986        initializeAndAddNetworkAndVerifySuccess();
987        when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(false);
988        when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(false);
989
990        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
991        mLooper.dispatchAll();
992        verify(mWifiNative).removeAllNetworks();
993
994        mLooper.startAutoDispatch();
995        assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
996        mLooper.stopAutoDispatch();
997
998        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
999        verify(mWifiConnectivityManager, never()).setUserConnectChoice(eq(0));
1000
1001        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
1002        mLooper.dispatchAll();
1003
1004        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1005                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1006        mLooper.dispatchAll();
1007
1008        assertEquals("ObtainingIpState", getCurrentState().getName());
1009
1010        DhcpResults dhcpResults = new DhcpResults();
1011        dhcpResults.setGateway("1.2.3.4");
1012        dhcpResults.setIpAddress("192.168.1.100", 0);
1013        dhcpResults.addDns("8.8.8.8");
1014        dhcpResults.setLeaseDuration(3600);
1015
1016        injectDhcpSuccess(dhcpResults);
1017        mLooper.dispatchAll();
1018
1019        assertEquals("ConnectedState", getCurrentState().getName());
1020    }
1021
1022    @Test
1023    public void enableWithInvalidNetworkId() throws Exception {
1024        initializeAndAddNetworkAndVerifySuccess();
1025        when(mWifiConfigManager.getConfiguredNetwork(eq(0))).thenReturn(null);
1026
1027        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1028        mLooper.dispatchAll();
1029        verify(mWifiNative).removeAllNetworks();
1030
1031        mLooper.startAutoDispatch();
1032        assertFalse(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
1033        mLooper.stopAutoDispatch();
1034
1035        verify(mWifiConfigManager, never()).enableNetwork(eq(0), eq(true), anyInt());
1036        verify(mWifiConfigManager, never()).checkAndUpdateLastConnectUid(eq(0), anyInt());
1037    }
1038
1039    /**
1040     * If caller tries to connect to a network that is already connected, the connection request
1041     * should succeed.
1042     *
1043     * Test: Create and connect to a network, then try to reconnect to the same network. Verify
1044     * that connection request returns with CONNECT_NETWORK_SUCCEEDED.
1045     */
1046    @Test
1047    public void reconnectToConnectedNetwork() throws Exception {
1048        initializeAndAddNetworkAndVerifySuccess();
1049
1050        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1051        mLooper.dispatchAll();
1052        verify(mWifiNative).removeAllNetworks();
1053
1054        mLooper.startAutoDispatch();
1055        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1056        mLooper.stopAutoDispatch();
1057
1058        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1059
1060        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
1061        mLooper.dispatchAll();
1062
1063        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1064                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1065        mLooper.dispatchAll();
1066
1067        assertEquals("ObtainingIpState", getCurrentState().getName());
1068
1069        // try to reconnect
1070        mLooper.startAutoDispatch();
1071        Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.CONNECT_NETWORK, 0);
1072        mLooper.stopAutoDispatch();
1073
1074        assertEquals(WifiManager.CONNECT_NETWORK_SUCCEEDED, reply.what);
1075    }
1076
1077    @Test
1078    public void testDhcpFailure() throws Exception {
1079        initializeAndAddNetworkAndVerifySuccess();
1080
1081        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1082        mLooper.dispatchAll();
1083
1084        mLooper.startAutoDispatch();
1085        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1086        mLooper.stopAutoDispatch();
1087
1088        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1089
1090        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
1091        mLooper.dispatchAll();
1092
1093        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1094                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1095        mLooper.dispatchAll();
1096
1097        assertEquals("ObtainingIpState", getCurrentState().getName());
1098
1099        injectDhcpFailure();
1100        mLooper.dispatchAll();
1101
1102        assertEquals("DisconnectingState", getCurrentState().getName());
1103    }
1104
1105    /**
1106     * Verify that the network selection status will be updated with DISABLED_AUTHENTICATION_FAILURE
1107     * when wrong password authentication failure is detected and the network had been
1108     * connected previously.
1109     */
1110    @Test
1111    public void testWrongPasswordWithPreviouslyConnected() throws Exception {
1112        initializeAndAddNetworkAndVerifySuccess();
1113
1114        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1115        mLooper.dispatchAll();
1116
1117        mLooper.startAutoDispatch();
1118        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1119        mLooper.stopAutoDispatch();
1120
1121        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1122
1123        WifiConfiguration config = new WifiConfiguration();
1124        config.getNetworkSelectionStatus().setHasEverConnected(true);
1125        when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
1126
1127        mWsm.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0,
1128                WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
1129        mLooper.dispatchAll();
1130
1131        verify(mWrongPasswordNotifier, never()).onWrongPasswordError(anyString());
1132        verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
1133                eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE));
1134
1135        assertEquals("DisconnectedState", getCurrentState().getName());
1136    }
1137
1138    /**
1139     * Verify that the network selection status will be updated with DISABLED_BY_WRONG_PASSWORD
1140     * when wrong password authentication failure is detected and the network has never been
1141     * connected.
1142     */
1143    @Test
1144    public void testWrongPasswordWithNeverConnected() throws Exception {
1145        initializeAndAddNetworkAndVerifySuccess();
1146
1147        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1148        mLooper.dispatchAll();
1149
1150        mLooper.startAutoDispatch();
1151        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1152        mLooper.stopAutoDispatch();
1153
1154        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1155
1156        WifiConfiguration config = new WifiConfiguration();
1157        config.SSID = sSSID;
1158        config.getNetworkSelectionStatus().setHasEverConnected(false);
1159        when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
1160
1161        mWsm.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0,
1162                WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
1163        mLooper.dispatchAll();
1164
1165        verify(mWrongPasswordNotifier).onWrongPasswordError(eq(sSSID));
1166        verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
1167                eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD));
1168
1169        assertEquals("DisconnectedState", getCurrentState().getName());
1170    }
1171
1172    /**
1173     * Verify that the network selection status will be updated with DISABLED_BY_WRONG_PASSWORD
1174     * when wrong password authentication failure is detected and the network is unknown.
1175     */
1176    @Test
1177    public void testWrongPasswordWithNullNetwork() throws Exception {
1178        initializeAndAddNetworkAndVerifySuccess();
1179
1180        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1181        mLooper.dispatchAll();
1182
1183        mLooper.startAutoDispatch();
1184        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1185        mLooper.stopAutoDispatch();
1186
1187        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1188
1189        when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null);
1190
1191        mWsm.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0,
1192                WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
1193        mLooper.dispatchAll();
1194
1195        verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
1196                eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD));
1197
1198        assertEquals("DisconnectedState", getCurrentState().getName());
1199    }
1200
1201    @Test
1202    public void testBadNetworkEvent() throws Exception {
1203        initializeAndAddNetworkAndVerifySuccess();
1204
1205        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1206        mLooper.dispatchAll();
1207
1208        mLooper.startAutoDispatch();
1209        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
1210        mLooper.stopAutoDispatch();
1211
1212        verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
1213
1214        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 0, sBSSID);
1215        mLooper.dispatchAll();
1216
1217        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1218                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1219        mLooper.dispatchAll();
1220
1221        assertEquals("DisconnectedState", getCurrentState().getName());
1222    }
1223
1224
1225    @Test
1226    public void smToString() throws Exception {
1227        assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString(
1228                AsyncChannel.CMD_CHANNEL_HALF_CONNECTED));
1229        assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString(
1230                DhcpClient.CMD_PRE_DHCP_ACTION));
1231        assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString(
1232                WifiStateMachine.CMD_IP_REACHABILITY_LOST));
1233    }
1234
1235    @Test
1236    public void disconnect() throws Exception {
1237        connect();
1238
1239        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06");
1240        mLooper.dispatchAll();
1241        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1242                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED));
1243        mLooper.dispatchAll();
1244
1245        assertEquals("DisconnectedState", getCurrentState().getName());
1246    }
1247
1248    /**
1249     * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected
1250     * to true.
1251     *
1252     * Test: Successfully create and connect to a network. Check the config and verify
1253     * WifiConfiguration.getHasEverConnected() is true.
1254     */
1255    @Test
1256    public void setHasEverConnectedTrueOnConnect() throws Exception {
1257        connect();
1258        verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(0);
1259    }
1260
1261    /**
1262     * Fail network connection attempt and verify HasEverConnected remains false.
1263     *
1264     * Test: Successfully create a network but fail when connecting. Check the config and verify
1265     * WifiConfiguration.getHasEverConnected() is false.
1266     */
1267    @Test
1268    public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception {
1269        testDhcpFailure();
1270        verify(mWifiConfigManager, never()).updateNetworkAfterConnect(0);
1271    }
1272
1273    @Test
1274    public void iconQueryTest() throws Exception {
1275        // TODO(b/31065385): Passpoint config management.
1276    }
1277
1278    @Test
1279    public void verboseLogRecSizeIsGreaterThanNormalSize() {
1280        assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > WifiStateMachine.NUM_LOG_RECS_NORMAL);
1281    }
1282
1283    /**
1284     * Verifies that, by default, we allow only the "normal" number of log records.
1285     */
1286    @Test
1287    public void normalLogRecSizeIsUsedByDefault() {
1288        assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize());
1289    }
1290
1291    /**
1292     * Verifies that, in verbose mode, we allow a larger number of log records.
1293     */
1294    @Test
1295    public void enablingVerboseLoggingUpdatesLogRecSize() {
1296        mWsm.enableVerboseLogging(1);
1297        assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mWsm.getLogRecMaxSize());
1298    }
1299
1300    @Test
1301    public void disablingVerboseLoggingClearsRecords() {
1302        mWsm.sendMessage(WifiStateMachine.CMD_DISCONNECT);
1303        mLooper.dispatchAll();
1304        assertTrue(mWsm.getLogRecSize() >= 1);
1305
1306        mWsm.enableVerboseLogging(0);
1307        assertEquals(0, mWsm.getLogRecSize());
1308    }
1309
1310    @Test
1311    public void disablingVerboseLoggingUpdatesLogRecSize() {
1312        mWsm.enableVerboseLogging(1);
1313        mWsm.enableVerboseLogging(0);
1314        assertEquals(WifiStateMachine.NUM_LOG_RECS_NORMAL, mWsm.getLogRecMaxSize());
1315    }
1316
1317    @Test
1318    public void logRecsIncludeDisconnectCommand() {
1319        // There's nothing special about the DISCONNECT command. It's just representative of
1320        // "normal" commands.
1321        mWsm.sendMessage(WifiStateMachine.CMD_DISCONNECT);
1322        mLooper.dispatchAll();
1323        assertEquals(1, mWsm.copyLogRecs()
1324                .stream()
1325                .filter(logRec -> logRec.getWhat() == WifiStateMachine.CMD_DISCONNECT)
1326                .count());
1327    }
1328
1329    @Test
1330    public void logRecsExcludeRssiPollCommandByDefault() {
1331        mWsm.sendMessage(WifiStateMachine.CMD_RSSI_POLL);
1332        mLooper.dispatchAll();
1333        assertEquals(0, mWsm.copyLogRecs()
1334                .stream()
1335                .filter(logRec -> logRec.getWhat() == WifiStateMachine.CMD_RSSI_POLL)
1336                .count());
1337    }
1338
1339    @Test
1340    public void logRecsIncludeRssiPollCommandWhenVerboseLoggingIsEnabled() {
1341        mWsm.enableVerboseLogging(1);
1342        mWsm.sendMessage(WifiStateMachine.CMD_RSSI_POLL);
1343        mLooper.dispatchAll();
1344        assertEquals(1, mWsm.copyLogRecs()
1345                .stream()
1346                .filter(logRec -> logRec.getWhat() == WifiStateMachine.CMD_RSSI_POLL)
1347                .count());
1348    }
1349
1350    /** Verifies that enabling verbose logging sets the hal log property in eng builds. */
1351    @Test
1352    public void enablingVerboseLoggingSetsHalLogPropertyInEngBuilds() {
1353        reset(mPropertyService);  // Ignore calls made in setUp()
1354        when(mBuildProperties.isEngBuild()).thenReturn(true);
1355        when(mBuildProperties.isUserdebugBuild()).thenReturn(false);
1356        when(mBuildProperties.isUserBuild()).thenReturn(false);
1357        mWsm.enableVerboseLogging(1);
1358        verify(mPropertyService).set("log.tag.WifiHAL", "V");
1359    }
1360
1361    /** Verifies that enabling verbose logging sets the hal log property in userdebug builds. */
1362    @Test
1363    public void enablingVerboseLoggingSetsHalLogPropertyInUserdebugBuilds() {
1364        reset(mPropertyService);  // Ignore calls made in setUp()
1365        when(mBuildProperties.isUserdebugBuild()).thenReturn(true);
1366        when(mBuildProperties.isEngBuild()).thenReturn(false);
1367        when(mBuildProperties.isUserBuild()).thenReturn(false);
1368        mWsm.enableVerboseLogging(1);
1369        verify(mPropertyService).set("log.tag.WifiHAL", "V");
1370    }
1371
1372    /** Verifies that enabling verbose logging does NOT set the hal log property in user builds. */
1373    @Test
1374    public void enablingVerboseLoggingDoeNotSetHalLogPropertyInUserBuilds() {
1375        reset(mPropertyService);  // Ignore calls made in setUp()
1376        when(mBuildProperties.isUserBuild()).thenReturn(true);
1377        when(mBuildProperties.isEngBuild()).thenReturn(false);
1378        when(mBuildProperties.isUserdebugBuild()).thenReturn(false);
1379        mWsm.enableVerboseLogging(1);
1380        verify(mPropertyService, never()).set(anyString(), anyString());
1381    }
1382
1383    private int testGetSupportedFeaturesCase(int supportedFeatures, boolean rttConfigured) {
1384        AsyncChannel channel = mock(AsyncChannel.class);
1385        Message reply = Message.obtain();
1386        reply.arg1 = supportedFeatures;
1387        reset(mPropertyService);  // Ignore calls made in setUp()
1388        when(channel.sendMessageSynchronously(WifiStateMachine.CMD_GET_SUPPORTED_FEATURES))
1389                .thenReturn(reply);
1390        when(mPropertyService.getBoolean("config.disable_rtt", false))
1391                .thenReturn(rttConfigured);
1392        return mWsm.syncGetSupportedFeatures(channel);
1393    }
1394
1395    /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */
1396    @Test
1397    public void syncGetSupportedFeatures() {
1398        final int featureAware = WifiManager.WIFI_FEATURE_AWARE;
1399        final int featureInfra = WifiManager.WIFI_FEATURE_INFRA;
1400        final int featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT;
1401        final int featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT;
1402
1403        assertEquals(0, testGetSupportedFeaturesCase(0, false));
1404        assertEquals(0, testGetSupportedFeaturesCase(0, true));
1405        assertEquals(featureAware | featureInfra,
1406                testGetSupportedFeaturesCase(featureAware | featureInfra, false));
1407        assertEquals(featureAware | featureInfra,
1408                testGetSupportedFeaturesCase(featureAware | featureInfra, true));
1409        assertEquals(featureInfra | featureD2dRtt,
1410                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, false));
1411        assertEquals(featureInfra,
1412                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt, true));
1413        assertEquals(featureInfra | featureD2apRtt,
1414                testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, false));
1415        assertEquals(featureInfra,
1416                testGetSupportedFeaturesCase(featureInfra | featureD2apRtt, true));
1417        assertEquals(featureInfra | featureD2dRtt | featureD2apRtt,
1418                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, false));
1419        assertEquals(featureInfra,
1420                testGetSupportedFeaturesCase(featureInfra | featureD2dRtt | featureD2apRtt, true));
1421    }
1422
1423    /**
1424     * Verify that syncAddOrUpdatePasspointConfig will redirect calls to {@link PasspointManager}
1425     * and returning the result that's returned from {@link PasspointManager}.
1426     */
1427    @Test
1428    public void syncAddOrUpdatePasspointConfig() throws Exception {
1429        PasspointConfiguration config = new PasspointConfiguration();
1430        HomeSp homeSp = new HomeSp();
1431        homeSp.setFqdn("test.com");
1432        config.setHomeSp(homeSp);
1433
1434        when(mPasspointManager.addOrUpdateProvider(config, MANAGED_PROFILE_UID)).thenReturn(true);
1435        mLooper.startAutoDispatch();
1436        assertTrue(mWsm.syncAddOrUpdatePasspointConfig(
1437                mWsmAsyncChannel, config, MANAGED_PROFILE_UID));
1438        mLooper.stopAutoDispatch();
1439        reset(mPasspointManager);
1440
1441        when(mPasspointManager.addOrUpdateProvider(config, MANAGED_PROFILE_UID)).thenReturn(false);
1442        mLooper.startAutoDispatch();
1443        assertFalse(mWsm.syncAddOrUpdatePasspointConfig(
1444                mWsmAsyncChannel, config, MANAGED_PROFILE_UID));
1445        mLooper.stopAutoDispatch();
1446    }
1447
1448    /**
1449     * Verify that syncAddOrUpdatePasspointConfig will redirect calls to {@link PasspointManager}
1450     * and returning the result that's returned from {@link PasspointManager} when in client mode.
1451     */
1452    @Test
1453    public void syncAddOrUpdatePasspointConfigInClientMode() throws Exception {
1454        loadComponentsInStaMode();
1455        syncAddOrUpdatePasspointConfig();
1456    }
1457
1458    /**
1459     * Verify that syncRemovePasspointConfig will redirect calls to {@link PasspointManager}
1460     * and returning the result that's returned from {@link PasspointManager}.
1461     */
1462    @Test
1463    public void syncRemovePasspointConfig() throws Exception {
1464        String fqdn = "test.com";
1465        when(mPasspointManager.removeProvider(fqdn)).thenReturn(true);
1466        mLooper.startAutoDispatch();
1467        assertTrue(mWsm.syncRemovePasspointConfig(mWsmAsyncChannel, fqdn));
1468        mLooper.stopAutoDispatch();
1469        reset(mPasspointManager);
1470
1471        when(mPasspointManager.removeProvider(fqdn)).thenReturn(false);
1472        mLooper.startAutoDispatch();
1473        assertFalse(mWsm.syncRemovePasspointConfig(mWsmAsyncChannel, fqdn));
1474        mLooper.stopAutoDispatch();
1475    }
1476
1477    /**
1478     * Verify that syncRemovePasspointConfig will redirect calls to {@link PasspointManager}
1479     * and returning the result that's returned from {@link PasspointManager} when in client mode.
1480     */
1481    @Test
1482    public void syncRemovePasspointConfigInClientMode() throws Exception {
1483        loadComponentsInStaMode();
1484        syncRemovePasspointConfig();
1485    }
1486
1487    /**
1488     * Verify that syncGetPasspointConfigs will redirect calls to {@link PasspointManager}
1489     * and returning the result that's returned from {@link PasspointManager}.
1490     */
1491    @Test
1492    public void syncGetPasspointConfigs() throws Exception {
1493        // Setup expected configs.
1494        List<PasspointConfiguration> expectedConfigs = new ArrayList<>();
1495        PasspointConfiguration config = new PasspointConfiguration();
1496        HomeSp homeSp = new HomeSp();
1497        homeSp.setFqdn("test.com");
1498        config.setHomeSp(homeSp);
1499        expectedConfigs.add(config);
1500
1501        when(mPasspointManager.getProviderConfigs()).thenReturn(expectedConfigs);
1502        mLooper.startAutoDispatch();
1503        assertEquals(expectedConfigs, mWsm.syncGetPasspointConfigs(mWsmAsyncChannel));
1504        mLooper.stopAutoDispatch();
1505        reset(mPasspointManager);
1506
1507        when(mPasspointManager.getProviderConfigs())
1508                .thenReturn(new ArrayList<PasspointConfiguration>());
1509        mLooper.startAutoDispatch();
1510        assertTrue(mWsm.syncGetPasspointConfigs(mWsmAsyncChannel).isEmpty());
1511        mLooper.stopAutoDispatch();
1512    }
1513
1514    /**
1515     * Verify that syncGetMatchingWifiConfig will redirect calls to {@link PasspointManager}
1516     * with expected {@link WifiConfiguration} being returned when in client mode.
1517     *
1518     * @throws Exception
1519     */
1520    @Test
1521    public void syncGetMatchingWifiConfigInClientMode() throws Exception {
1522        loadComponentsInStaMode();
1523
1524        when(mPasspointManager.getMatchingWifiConfig(any(ScanResult.class))).thenReturn(null);
1525        mLooper.startAutoDispatch();
1526        assertNull(mWsm.syncGetMatchingWifiConfig(new ScanResult(), mWsmAsyncChannel));
1527        mLooper.stopAutoDispatch();
1528        reset(mPasspointManager);
1529
1530        WifiConfiguration expectedConfig = new WifiConfiguration();
1531        expectedConfig.SSID = "TestSSID";
1532        when(mPasspointManager.getMatchingWifiConfig(any(ScanResult.class)))
1533                .thenReturn(expectedConfig);
1534        mLooper.startAutoDispatch();
1535        WifiConfiguration actualConfig = mWsm.syncGetMatchingWifiConfig(new ScanResult(),
1536                mWsmAsyncChannel);
1537        mLooper.stopAutoDispatch();
1538        assertEquals(expectedConfig.SSID, actualConfig.SSID);
1539    }
1540
1541    /**
1542     * Verify that syncGetMatchingWifiConfig will be a no-op and return {@code null} when not in
1543     * client mode.
1544     *
1545     * @throws Exception
1546     */
1547    @Test
1548    public void syncGetMatchingWifiConfigInNonClientMode() throws Exception {
1549        mLooper.startAutoDispatch();
1550        assertNull(mWsm.syncGetMatchingWifiConfig(new ScanResult(), mWsmAsyncChannel));
1551        mLooper.stopAutoDispatch();
1552        verify(mPasspointManager, never()).getMatchingWifiConfig(any(ScanResult.class));
1553    }
1554
1555    /**
1556     * Sunny-day scenario for WPS connections. Verifies that after a START_WPS and
1557     * NETWORK_CONNECTION_EVENT command, WifiStateMachine will have transitioned to ObtainingIpState
1558     */
1559    @Test
1560    public void wpsPbcConnectSuccess() throws Exception {
1561        loadComponentsInStaMode();
1562        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1563        mLooper.dispatchAll();
1564        assertEquals("DisconnectedState", getCurrentState().getName());
1565
1566        WpsInfo wpsInfo = new WpsInfo();
1567        wpsInfo.setup = WpsInfo.PBC;
1568        wpsInfo.BSSID = sBSSID;
1569        when(mWifiNative.removeAllNetworks()).thenReturn(true);
1570        when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
1571        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1572        mLooper.dispatchAll();
1573        assertEquals("WpsRunningState", getCurrentState().getName());
1574
1575        setupMocksForWpsNetworkMigration();
1576        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1577        mLooper.dispatchAll();
1578        assertEquals("ObtainingIpState", getCurrentState().getName());
1579        verifyMocksForWpsNetworkMigration();
1580    }
1581
1582    /**
1583     * Verify failure in starting Wps PBC network connection.
1584     */
1585    @Test
1586    public void wpsPbcConnectFailure() throws Exception {
1587        loadComponentsInStaMode();
1588        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1589        mLooper.dispatchAll();
1590
1591        when(mWifiNative.startWpsPbc(eq(sBSSID))).thenReturn(false);
1592        WpsInfo wpsInfo = new WpsInfo();
1593        wpsInfo.setup = WpsInfo.PBC;
1594        wpsInfo.BSSID = sBSSID;
1595
1596        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1597        mLooper.dispatchAll();
1598        verify(mWifiNative).startWpsPbc(eq(sBSSID));
1599
1600        assertFalse("WpsRunningState".equals(getCurrentState().getName()));
1601    }
1602
1603    /**
1604     * Verify that if Supplicant generates multiple networks for a WPS configuration,
1605     * WifiStateMachine cycles into DisconnectedState
1606     */
1607    @Test
1608    public void wpsPbcConnectFailure_tooManyConfigs() throws Exception {
1609        loadComponentsInStaMode();
1610        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1611        mLooper.dispatchAll();
1612        assertEquals("DisconnectedState", getCurrentState().getName());
1613
1614        WpsInfo wpsInfo = new WpsInfo();
1615        wpsInfo.setup = WpsInfo.PBC;
1616        wpsInfo.BSSID = sBSSID;
1617        when(mWifiNative.removeAllNetworks()).thenReturn(true);
1618        when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
1619        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1620        mLooper.dispatchAll();
1621        assertEquals("WpsRunningState", getCurrentState().getName());
1622
1623        setupMocksForWpsNetworkMigration();
1624        doAnswer(new AnswerWithArguments() {
1625            public boolean answer(Map<String, WifiConfiguration> configs,
1626                                  SparseArray<Map<String, String>> networkExtras) throws Exception {
1627                configs.put("dummy1", new WifiConfiguration());
1628                configs.put("dummy2", new WifiConfiguration());
1629                return true;
1630            }
1631        }).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
1632        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1633        mLooper.dispatchAll();
1634        assertTrue("DisconnectedState".equals(getCurrentState().getName()));
1635    }
1636
1637    /**
1638     * Verify that when supplicant fails to load networks during WPS, WifiStateMachine cycles into
1639     * DisconnectedState
1640     */
1641    @Test
1642    public void wpsPbcConnectFailure_migrateNetworksFailure() throws Exception {
1643        loadComponentsInStaMode();
1644        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1645        mLooper.dispatchAll();
1646        assertEquals("DisconnectedState", getCurrentState().getName());
1647
1648        WpsInfo wpsInfo = new WpsInfo();
1649        wpsInfo.setup = WpsInfo.PBC;
1650        wpsInfo.BSSID = sBSSID;
1651        when(mWifiNative.removeAllNetworks()).thenReturn(true);
1652        when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
1653        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1654        mLooper.dispatchAll();
1655        assertEquals("WpsRunningState", getCurrentState().getName());
1656
1657        setupMocksForWpsNetworkMigration();
1658        when(mWifiNative.migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class)))
1659                .thenReturn(false);
1660        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1661        mLooper.dispatchAll();
1662        assertEquals("DisconnectedState", getCurrentState().getName());
1663    }
1664
1665    /**
1666     * Verify successful Wps Pin Display network connection.
1667     */
1668    @Test
1669    public void wpsPinDisplayConnectSuccess() throws Exception {
1670        loadComponentsInStaMode();
1671        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1672        mLooper.dispatchAll();
1673
1674        when(mWifiNative.startWpsPinDisplay(eq(sBSSID))).thenReturn("34545434");
1675        WpsInfo wpsInfo = new WpsInfo();
1676        wpsInfo.setup = WpsInfo.DISPLAY;
1677        wpsInfo.BSSID = sBSSID;
1678
1679        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1680        mLooper.dispatchAll();
1681        verify(mWifiNative).startWpsPinDisplay(eq(sBSSID));
1682
1683        assertEquals("WpsRunningState", getCurrentState().getName());
1684
1685        setupMocksForWpsNetworkMigration();
1686
1687        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
1688        mLooper.dispatchAll();
1689
1690        assertEquals("ObtainingIpState", getCurrentState().getName());
1691        verifyMocksForWpsNetworkMigration();
1692    }
1693
1694    /**
1695     * Verify failure in Wps Pin Display network connection.
1696     */
1697    @Test
1698    public void wpsPinDisplayConnectFailure() throws Exception {
1699        loadComponentsInStaMode();
1700        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1701        mLooper.dispatchAll();
1702
1703        when(mWifiNative.startWpsPinDisplay(eq(sBSSID))).thenReturn(null);
1704        WpsInfo wpsInfo = new WpsInfo();
1705        wpsInfo.setup = WpsInfo.DISPLAY;
1706        wpsInfo.BSSID = sBSSID;
1707
1708        mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
1709        mLooper.dispatchAll();
1710        verify(mWifiNative).startWpsPinDisplay(eq(sBSSID));
1711
1712        assertFalse("WpsRunningState".equals(getCurrentState().getName()));
1713    }
1714
1715    @Test
1716    public void handleVendorHalDeath() throws Exception {
1717        ArgumentCaptor<WifiNative.VendorHalDeathEventHandler> deathHandlerCapturer =
1718                ArgumentCaptor.forClass(WifiNative.VendorHalDeathEventHandler.class);
1719        when(mWifiNative.initializeVendorHal(deathHandlerCapturer.capture())).thenReturn(true);
1720
1721        // Trigger initialize to capture the death handler registration.
1722        mLooper.startAutoDispatch();
1723        assertTrue(mWsm.syncInitialize(mWsmAsyncChannel));
1724        mLooper.stopAutoDispatch();
1725
1726        verify(mWifiNative).initializeVendorHal(any(WifiNative.VendorHalDeathEventHandler.class));
1727        WifiNative.VendorHalDeathEventHandler deathHandler = deathHandlerCapturer.getValue();
1728
1729        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1730        mLooper.dispatchAll();
1731
1732        // Now trigger the death notification.
1733        deathHandler.onDeath();
1734        mLooper.dispatchAll();
1735
1736        verify(mWifiMetrics).incrementNumHalCrashes();
1737        verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_HAL_CRASH));
1738    }
1739
1740    @Test
1741    public void handleWificondDeath() throws Exception {
1742        ArgumentCaptor<StateMachineDeathRecipient> deathHandlerCapturer =
1743                ArgumentCaptor.forClass(StateMachineDeathRecipient.class);
1744
1745        // Trigger initialize to capture the death handler registration.
1746        loadComponentsInStaMode();
1747
1748        verify(mClientInterfaceBinder).linkToDeath(deathHandlerCapturer.capture(), anyInt());
1749        StateMachineDeathRecipient deathHandler = deathHandlerCapturer.getValue();
1750
1751        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1752        mLooper.dispatchAll();
1753
1754        // Now trigger the death notification.
1755        deathHandler.binderDied();
1756        mLooper.dispatchAll();
1757
1758        verify(mWifiMetrics).incrementNumWificondCrashes();
1759        verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_WIFICOND_CRASH));
1760    }
1761
1762    private void setupMocksForWpsNetworkMigration() {
1763        WifiConfiguration config = new WifiConfiguration();
1764        config.networkId = WPS_SUPPLICANT_NETWORK_ID;
1765        config.SSID = DEFAULT_TEST_SSID;
1766        doAnswer(new AnswerWithArguments() {
1767            public boolean answer(Map<String, WifiConfiguration> configs,
1768                                  SparseArray<Map<String, String>> networkExtras) throws Exception {
1769                configs.put("dummy", config);
1770                return true;
1771            }
1772        }).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
1773        when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
1774                .thenReturn(new NetworkUpdateResult(WPS_FRAMEWORK_NETWORK_ID));
1775        when(mWifiConfigManager.enableNetwork(eq(WPS_FRAMEWORK_NETWORK_ID), anyBoolean(), anyInt()))
1776                .thenReturn(true);
1777        when(mWifiNative.getFrameworkNetworkId(eq(WPS_FRAMEWORK_NETWORK_ID))).thenReturn(
1778                WPS_FRAMEWORK_NETWORK_ID);
1779        when(mWifiConfigManager.getConfiguredNetwork(eq(WPS_FRAMEWORK_NETWORK_ID))).thenReturn(
1780                config);
1781    }
1782
1783    private void verifyMocksForWpsNetworkMigration() {
1784        // Network Ids should be reset so that it is treated as addition.
1785        ArgumentCaptor<WifiConfiguration> wifiConfigCaptor =
1786                ArgumentCaptor.forClass(WifiConfiguration.class);
1787        verify(mWifiConfigManager).addOrUpdateNetwork(wifiConfigCaptor.capture(), anyInt());
1788        assertEquals(WifiConfiguration.INVALID_NETWORK_ID, wifiConfigCaptor.getValue().networkId);
1789        assertEquals(DEFAULT_TEST_SSID, wifiConfigCaptor.getValue().SSID);
1790        verify(mWifiConfigManager).enableNetwork(eq(WPS_FRAMEWORK_NETWORK_ID), anyBoolean(),
1791                anyInt());
1792    }
1793
1794    /**
1795     * Verifies that WifiInfo is cleared upon exiting and entering WifiInfo, and that it is not
1796     * updated by SUPPLICAN_STATE_CHANGE_EVENTs in ScanModeState.
1797     * This protects WifiStateMachine from  getting into a bad state where WifiInfo says wifi is
1798     * already Connected or Connecting, (when it is in-fact Disconnected), so
1799     * WifiConnectivityManager does not attempt any new Connections, freezing wifi.
1800     */
1801    @Test
1802    public void testWifiInfoCleanedUpEnteringExitingConnectModeState() throws Exception {
1803        InOrder inOrder = inOrder(mWifiConnectivityManager);
1804        Log.i(TAG, mWsm.getCurrentState().getName());
1805        String initialBSSID = "aa:bb:cc:dd:ee:ff";
1806        WifiInfo wifiInfo = mWsm.getWifiInfo();
1807        wifiInfo.setBSSID(initialBSSID);
1808
1809        // Set WSM to CONNECT_MODE and verify state, and wifi enabled in ConnectivityManager
1810        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1811        startSupplicantAndDispatchMessages();
1812        mWsm.setSupplicantRunning(true);
1813        mLooper.dispatchAll();
1814        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
1815        assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
1816        inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(true));
1817        assertNull(wifiInfo.getBSSID());
1818
1819        // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is updated
1820        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1821                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1822        mLooper.dispatchAll();
1823        assertEquals(sBSSID, wifiInfo.getBSSID());
1824        assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
1825
1826        // Set WSM to SCAN_ONLY_MODE, verify state and wifi disabled in ConnectivityManager, and
1827        // WifiInfo is reset() and state set to DISCONNECTED
1828        mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
1829        mLooper.dispatchAll();
1830        assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
1831        assertEquals("ScanModeState", getCurrentState().getName());
1832        assertEquals(WifiManager.WIFI_STATE_DISABLED, mWsm.syncGetWifiState());
1833        inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(false));
1834        assertNull(wifiInfo.getBSSID());
1835        assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
1836
1837        // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is not updated
1838        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1839                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
1840        mLooper.dispatchAll();
1841        assertNull(wifiInfo.getBSSID());
1842        assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
1843
1844        // Set the bssid to something, so we can verify it is cleared (just in case)
1845        wifiInfo.setBSSID(initialBSSID);
1846
1847        // Set WSM to CONNECT_MODE and verify state, and wifi enabled in ConnectivityManager,
1848        // and WifiInfo has been reset
1849        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1850        mLooper.dispatchAll();
1851        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
1852        assertEquals(WifiManager.WIFI_STATE_ENABLED, mWsm.syncGetWifiState());
1853        inOrder.verify(mWifiConnectivityManager).setWifiEnabled(eq(true));
1854        assertEquals("DisconnectedState", getCurrentState().getName());
1855        assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
1856        assertNull(wifiInfo.getBSSID());
1857    }
1858
1859    /**
1860     * Test that the process uid has full wifiInfo access.
1861     * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
1862     * returns a copy of WifiInfo.
1863     */
1864    @Test
1865    public void testConnectedIdsAreVisibleFromOwnUid() throws Exception {
1866        assertEquals(Process.myUid(), Binder.getCallingUid());
1867        WifiInfo wifiInfo = mWsm.getWifiInfo();
1868        wifiInfo.setBSSID(sBSSID);
1869        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
1870
1871        connect();
1872        WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
1873
1874        assertNotEquals(wifiInfo, connectionInfo);
1875        assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
1876        assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
1877    }
1878
1879    /**
1880     * Test that connected SSID and BSSID are not exposed to an app that does not have the
1881     * appropriate permissions.
1882     * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
1883     * returns a copy of WifiInfo.
1884     */
1885    @Test
1886    public void testConnectedIdsAreHiddenFromRandomApp() throws Exception {
1887        int actualUid = Binder.getCallingUid();
1888        int fakeUid = Process.myUid() + 100000;
1889        assertNotEquals(actualUid, fakeUid);
1890        BinderUtil.setUid(fakeUid);
1891        try {
1892            WifiInfo wifiInfo = mWsm.getWifiInfo();
1893
1894            // Get into a connected state, with known BSSID and SSID
1895            connect();
1896            assertEquals(sBSSID, wifiInfo.getBSSID());
1897            assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
1898
1899            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
1900                    .thenReturn(false);
1901
1902            WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
1903
1904            assertNotEquals(wifiInfo, connectionInfo);
1905            assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
1906            assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
1907        } finally {
1908            BinderUtil.setUid(actualUid);
1909        }
1910    }
1911
1912    /**
1913     * Test that connected SSID and BSSID are not exposed to an app that does not have the
1914     * appropriate permissions, when canAccessScanResults raises a SecurityException.
1915     * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
1916     * returns a copy of WifiInfo.
1917     */
1918    @Test
1919    public void testConnectedIdsAreHiddenOnSecurityException() throws Exception {
1920        int actualUid = Binder.getCallingUid();
1921        int fakeUid = Process.myUid() + 100000;
1922        assertNotEquals(actualUid, fakeUid);
1923        BinderUtil.setUid(fakeUid);
1924        try {
1925            WifiInfo wifiInfo = mWsm.getWifiInfo();
1926
1927            // Get into a connected state, with known BSSID and SSID
1928            connect();
1929            assertEquals(sBSSID, wifiInfo.getBSSID());
1930            assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
1931
1932            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
1933                    .thenThrow(new SecurityException());
1934
1935            WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
1936
1937            assertNotEquals(wifiInfo, connectionInfo);
1938            assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
1939            assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
1940        } finally {
1941            BinderUtil.setUid(actualUid);
1942        }
1943    }
1944
1945    /**
1946     * Test that connected SSID and BSSID are exposed to an app that does have the
1947     * appropriate permissions.
1948     */
1949    @Test
1950    public void testConnectedIdsAreVisibleFromPermittedApp() throws Exception {
1951        int actualUid = Binder.getCallingUid();
1952        int fakeUid = Process.myUid() + 100000;
1953        BinderUtil.setUid(fakeUid);
1954        try {
1955            WifiInfo wifiInfo = mWsm.getWifiInfo();
1956
1957            // Get into a connected state, with known BSSID and SSID
1958            connect();
1959            assertEquals(sBSSID, wifiInfo.getBSSID());
1960            assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
1961
1962            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
1963                    .thenReturn(true);
1964
1965            WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
1966
1967            assertNotEquals(wifiInfo, connectionInfo);
1968            assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
1969            assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
1970            // Access to our MAC address uses a different permission, make sure it is not granted
1971            assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
1972        } finally {
1973            BinderUtil.setUid(actualUid);
1974        }
1975    }
1976
1977    /**
1978     * Adds the network without putting WifiStateMachine into ConnectMode.
1979     */
1980    @Test
1981    public void addNetworkInInitialState() throws Exception {
1982        // We should not be in initial state now.
1983        assertTrue("InitialState".equals(getCurrentState().getName()));
1984        addNetworkAndVerifySuccess(false);
1985        verify(mWifiConnectivityManager, never()).setUserConnectChoice(eq(0));
1986    }
1987
1988    /**
1989     * Test START_WPS with a null wpsInfo object fails gracefully (No NPE)
1990     */
1991    @Test
1992    public void testStartWps_nullWpsInfo() throws Exception {
1993        loadComponentsInStaMode();
1994        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
1995        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
1996        assertEquals("DisconnectedState", getCurrentState().getName());
1997        mLooper.startAutoDispatch();
1998        Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.START_WPS, 0, 0,
1999                null);
2000        mLooper.stopAutoDispatch();
2001        assertEquals(WifiManager.WPS_FAILED, reply.what);
2002    }
2003
2004    /**
2005     * Test that DISABLE_NETWORK returns failure to public API when WifiConfigManager returns
2006     * failure.
2007     */
2008    @Test
2009    public void testSyncDisableNetwork_failure() throws Exception {
2010        loadComponentsInStaMode();
2011        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2012        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2013        assertEquals("DisconnectedState", getCurrentState().getName());
2014        when(mWifiConfigManager.disableNetwork(anyInt(), anyInt())).thenReturn(false);
2015
2016        mLooper.startAutoDispatch();
2017        boolean succeeded = mWsm.syncDisableNetwork(mWsmAsyncChannel, 0);
2018        mLooper.stopAutoDispatch();
2019        assertFalse(succeeded);
2020    }
2021
2022    /**
2023     * Test that failure to start HAL in AP mode increments the corresponding metrics.
2024     */
2025    @Test
2026    public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
2027        when(mWifiNative.setupForSoftApMode())
2028                .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
2029
2030        SoftApModeConfiguration config = new SoftApModeConfiguration(
2031                WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
2032        mWsm.setHostApRunning(config, true);
2033        mLooper.dispatchAll();
2034
2035        verify(mWifiNative).setupForSoftApMode();
2036        verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
2037    }
2038
2039    /**
2040     * Test that failure to start HAL in AP mode increments the corresponding metrics.
2041     */
2042    @Test
2043    public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
2044        when(mWifiNative.setupForSoftApMode())
2045                .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
2046
2047        SoftApModeConfiguration config = new SoftApModeConfiguration(
2048                WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
2049        mWsm.setHostApRunning(config, true);
2050        mLooper.dispatchAll();
2051
2052        verify(mWifiNative).setupForSoftApMode();
2053        verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
2054    }
2055
2056    /**
2057     * Test that failure to start HAL in client mode increments the corresponding metrics.
2058     */
2059    @Test
2060    public void testSetupForClientModeHalFailureIncrementsMetrics() throws Exception {
2061        when(mWifiNative.setupForClientMode())
2062                .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
2063
2064        mWsm.setSupplicantRunning(true);
2065        mLooper.dispatchAll();
2066
2067        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
2068        mLooper.dispatchAll();
2069
2070        verify(mWifiNative).setupForClientMode();
2071        verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
2072    }
2073
2074    /**
2075     * Test that failure to start HAL in client mode increments the corresponding metrics.
2076     */
2077    @Test
2078    public void testSetupForClientModeWificondFailureIncrementsMetrics() throws Exception {
2079        when(mWifiNative.setupForClientMode())
2080                .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
2081
2082        mWsm.setSupplicantRunning(true);
2083        mLooper.dispatchAll();
2084
2085        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
2086        mLooper.dispatchAll();
2087
2088        verify(mWifiNative).setupForClientMode();
2089        verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
2090    }
2091
2092    /**
2093     * Test that we don't register the telephony call state listener on devices which do not support
2094     * setting/resetting Tx power limit.
2095     */
2096    @Test
2097    public void testVoiceCallSar_disabledTxPowerScenario_WifiOn() throws Exception {
2098        loadComponentsInStaMode();
2099        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2100        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2101        assertEquals("DisconnectedState", getCurrentState().getName());
2102        assertNull(mPhoneStateListener);
2103    }
2104
2105    /**
2106     * Test that we do register the telephony call state listener on devices which do support
2107     * setting/resetting Tx power limit.
2108     */
2109    @Test
2110    public void testVoiceCallSar_enabledTxPowerScenario_WifiOn() throws Exception {
2111        mResources.setBoolean(
2112                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
2113        initializeWsm();
2114
2115        loadComponentsInStaMode();
2116        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2117        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2118        assertEquals("DisconnectedState", getCurrentState().getName());
2119        assertNotNull(mPhoneStateListener);
2120    }
2121
2122    /**
2123     * Test that we do register the telephony call state listener on devices which do support
2124     * setting/resetting Tx power limit and set the tx power level if we're in state
2125     * {@link TelephonyManager#CALL_STATE_OFFHOOK}.
2126     */
2127    @Test
2128    public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn()
2129            throws Exception {
2130        mResources.setBoolean(
2131                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
2132        initializeWsm();
2133
2134        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
2135        when(mTelephonyManager.isOffhook()).thenReturn(true);
2136
2137        loadComponentsInStaMode();
2138        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2139        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2140        assertEquals("DisconnectedState", getCurrentState().getName());
2141        assertNotNull(mPhoneStateListener);
2142        verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2143    }
2144
2145    /**
2146     * Test that we do register the telephony call state listener on devices which do support
2147     * setting/resetting Tx power limit and set the tx power level if we're in state
2148     * {@link TelephonyManager#CALL_STATE_IDLE}.
2149     */
2150    @Test
2151    public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiTurnedOn()
2152            throws Exception {
2153        mResources.setBoolean(
2154                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
2155        initializeWsm();
2156
2157        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
2158        when(mTelephonyManager.isIdle()).thenReturn(true);
2159
2160        loadComponentsInStaMode();
2161        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2162        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2163        assertEquals("DisconnectedState", getCurrentState().getName());
2164        assertNotNull(mPhoneStateListener);
2165    }
2166
2167    /**
2168     * Test that we do register the telephony call state listener on devices which do support
2169     * setting/resetting Tx power limit and set the tx power level if we're in state
2170     * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
2171     * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
2172     */
2173    @Test
2174    public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn_Fails()
2175            throws Exception {
2176        mResources.setBoolean(
2177                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
2178        initializeWsm();
2179
2180        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
2181        when(mTelephonyManager.isOffhook()).thenReturn(true);
2182
2183        loadComponentsInStaMode();
2184        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2185        assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
2186        assertEquals("DisconnectedState", getCurrentState().getName());
2187        assertNotNull(mPhoneStateListener);
2188        verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2189    }
2190
2191    /**
2192     * Test that we invoke the corresponding WifiNative method when
2193     * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
2194     * {@link TelephonyManager#CALL_STATE_OFFHOOK}.
2195     */
2196    @Test
2197    public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn()
2198            throws Exception {
2199        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
2200        testVoiceCallSar_enabledTxPowerScenario_WifiOn();
2201
2202        mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
2203        mLooper.dispatchAll();
2204        verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2205    }
2206
2207    /**
2208     * Test that we invoke the corresponding WifiNative method when
2209     * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
2210     * {@link TelephonyManager#CALL_STATE_IDLE}.
2211     */
2212    @Test
2213    public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiOn() throws Exception {
2214        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
2215        testVoiceCallSar_enabledTxPowerScenario_WifiOn();
2216
2217        mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
2218        mLooper.dispatchAll();
2219        verify(mWifiNative, atLeastOnce())
2220                .selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
2221    }
2222
2223    /**
2224     * Test that we invoke the corresponding WifiNative method when
2225     * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
2226     * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
2227     * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
2228     */
2229    @Test
2230    public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn_Fails()
2231            throws Exception {
2232        when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
2233        testVoiceCallSar_enabledTxPowerScenario_WifiOn();
2234
2235        mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
2236        mLooper.dispatchAll();
2237        verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2238    }
2239
2240    /**
2241     * Test that we don't invoke the corresponding WifiNative method when
2242     * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
2243     * {@link TelephonyManager#CALL_STATE_IDLE} or {@link TelephonyManager#CALL_STATE_OFFHOOK} when
2244     * wifi is off (state machine is not in SupplicantStarted state).
2245     */
2246    @Test
2247    public void testVoiceCallSar_enabledTxPowerScenarioCallState_WhenWifiOff() throws Exception {
2248        mResources.setBoolean(
2249                R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
2250        initializeWsm();
2251
2252        mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
2253        mLooper.dispatchAll();
2254        verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
2255
2256        mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
2257        mLooper.dispatchAll();
2258        verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
2259    }
2260
2261    /**
2262     * Verifies that a network disconnection event will result in WifiStateMachine invoking
2263     * {@link WifiConfigManager#removeAllEphemeralOrPasspointConfiguredNetworks()} to remove
2264     * any ephemeral or passpoint networks from it's internal database.
2265     */
2266    @Test
2267    public void testDisconnectionRemovesEphemeralAndPasspointNetworks() throws Exception {
2268        disconnect();
2269        verify(mWifiConfigManager).removeAllEphemeralOrPasspointConfiguredNetworks();
2270    }
2271
2272    /**
2273     * Verifies that WifiStateMachine sets and unsets appropriate 'RecentFailureReason' values
2274     * on a WifiConfiguration when it fails association, authentication, or successfully connects
2275     */
2276    @Test
2277    public void testExtraFailureReason_ApIsBusy() throws Exception {
2278        // Setup CONNECT_MODE & a WifiConfiguration
2279        initializeAndAddNetworkAndVerifySuccess();
2280        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
2281        mLooper.dispatchAll();
2282        // Trigger a connection to this (CMD_START_CONNECT will actually fail, but it sets up
2283        // targetNetworkId state)
2284        mWsm.sendMessage(WifiStateMachine.CMD_START_CONNECT, 0, 0, sBSSID);
2285        mLooper.dispatchAll();
2286        // Simulate an ASSOCIATION_REJECTION_EVENT, due to the AP being busy
2287        mWsm.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT, 0,
2288                ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, sBSSID);
2289        mLooper.dispatchAll();
2290        verify(mWifiConfigManager).setRecentFailureAssociationStatus(eq(0),
2291                eq(WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA));
2292        assertEquals("DisconnectedState", getCurrentState().getName());
2293
2294        // Simulate an AUTHENTICATION_FAILURE_EVENT, which should clear the ExtraFailureReason
2295        reset(mWifiConfigManager);
2296        mWsm.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0, 0, null);
2297        mLooper.dispatchAll();
2298        verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
2299        verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
2300
2301        // Simulate a NETWORK_CONNECTION_EVENT which should clear the ExtraFailureReason
2302        reset(mWifiConfigManager);
2303        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
2304        mLooper.dispatchAll();
2305        verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
2306        verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
2307    }
2308
2309    /**
2310     * Test that the helper method
2311     * {@link WifiStateMachine#shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration)}
2312     * returns true when we connect to the last selected network before expiration of
2313     * {@link WifiStateMachine#LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS}.
2314     */
2315    @Test
2316    public void testShouldEvaluateWhetherToSendExplicitlySelected_SameNetworkNotExpired() {
2317        long lastSelectedTimestamp = 45666743454L;
2318        int lastSelectedNetworkId = 5;
2319
2320        when(mClock.getElapsedSinceBootMillis()).thenReturn(
2321                lastSelectedTimestamp
2322                        + WifiStateMachine.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2323        when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(lastSelectedTimestamp);
2324        when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(lastSelectedNetworkId);
2325
2326        WifiConfiguration currentConfig = new WifiConfiguration();
2327        currentConfig.networkId = lastSelectedNetworkId;
2328        assertTrue(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
2329    }
2330
2331    /**
2332     * Test that the helper method
2333     * {@link WifiStateMachine#shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration)}
2334     * returns false when we connect to the last selected network after expiration of
2335     * {@link WifiStateMachine#LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS}.
2336     */
2337    @Test
2338    public void testShouldEvaluateWhetherToSendExplicitlySelected_SameNetworkExpired() {
2339        long lastSelectedTimestamp = 45666743454L;
2340        int lastSelectedNetworkId = 5;
2341
2342        when(mClock.getElapsedSinceBootMillis()).thenReturn(
2343                lastSelectedTimestamp
2344                        + WifiStateMachine.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS + 1);
2345        when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(lastSelectedTimestamp);
2346        when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(lastSelectedNetworkId);
2347
2348        WifiConfiguration currentConfig = new WifiConfiguration();
2349        currentConfig.networkId = lastSelectedNetworkId;
2350        assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
2351    }
2352
2353    /**
2354     * Test that the helper method
2355     * {@link WifiStateMachine#shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration)}
2356     * returns false when we connect to a different network to the last selected network.
2357     */
2358    @Test
2359    public void testShouldEvaluateWhetherToSendExplicitlySelected_DifferentNetwork() {
2360        long lastSelectedTimestamp = 45666743454L;
2361        int lastSelectedNetworkId = 5;
2362
2363        when(mClock.getElapsedSinceBootMillis()).thenReturn(
2364                lastSelectedTimestamp
2365                        + WifiStateMachine.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2366        when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(lastSelectedTimestamp);
2367        when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(lastSelectedNetworkId);
2368
2369        WifiConfiguration currentConfig = new WifiConfiguration();
2370        currentConfig.networkId = lastSelectedNetworkId - 1;
2371        assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
2372    }
2373}
2374