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