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 
17 package com.android.server.wifi;
18 
19 import static android.content.Intent.ACTION_SCREEN_OFF;
20 import static android.content.Intent.ACTION_SCREEN_ON;
21 import static android.net.NetworkInfo.DetailedState.CONNECTED;
22 import static android.net.NetworkInfo.DetailedState.CONNECTING;
23 import static android.net.NetworkInfo.DetailedState.OBTAINING_IPADDR;
24 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
25 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
26 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
27 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE;
28 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY;
29 
30 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
31 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
32 import static com.android.server.wifi.ClientModeImpl.CMD_PRE_DHCP_ACTION;
33 import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
34 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS;
35 
36 import static org.junit.Assert.assertArrayEquals;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertNotEquals;
40 import static org.junit.Assert.assertNotNull;
41 import static org.junit.Assert.assertNull;
42 import static org.junit.Assert.assertTrue;
43 import static org.junit.Assume.assumeTrue;
44 import static org.mockito.Mockito.any;
45 import static org.mockito.Mockito.anyBoolean;
46 import static org.mockito.Mockito.anyByte;
47 import static org.mockito.Mockito.anyInt;
48 import static org.mockito.Mockito.anyLong;
49 import static org.mockito.Mockito.anyObject;
50 import static org.mockito.Mockito.anyString;
51 import static org.mockito.Mockito.argThat;
52 import static org.mockito.Mockito.atLeastOnce;
53 import static org.mockito.Mockito.clearInvocations;
54 import static org.mockito.Mockito.doAnswer;
55 import static org.mockito.Mockito.doReturn;
56 import static org.mockito.Mockito.eq;
57 import static org.mockito.Mockito.inOrder;
58 import static org.mockito.Mockito.mock;
59 import static org.mockito.Mockito.never;
60 import static org.mockito.Mockito.reset;
61 import static org.mockito.Mockito.spy;
62 import static org.mockito.Mockito.times;
63 import static org.mockito.Mockito.verify;
64 import static org.mockito.Mockito.verifyNoMoreInteractions;
65 import static org.mockito.Mockito.when;
66 import static org.mockito.Mockito.withSettings;
67 
68 import android.annotation.NonNull;
69 import android.annotation.Nullable;
70 import android.app.ActivityManager;
71 import android.app.test.MockAnswerUtil.AnswerWithArguments;
72 import android.app.test.TestAlarmManager;
73 import android.content.BroadcastReceiver;
74 import android.content.Context;
75 import android.content.Intent;
76 import android.content.pm.PackageManager;
77 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
78 import android.hardware.wifi.supplicant.V1_4.ISupplicantStaIfaceCallback.AssociationRejectionData;
79 import android.hardware.wifi.supplicant.V1_4.ISupplicantStaIfaceCallback.MboAssocDisallowedReasonCode;
80 import android.net.CaptivePortalData;
81 import android.net.DhcpResultsParcelable;
82 import android.net.InetAddresses;
83 import android.net.Layer2InformationParcelable;
84 import android.net.Layer2PacketParcelable;
85 import android.net.LinkAddress;
86 import android.net.LinkProperties;
87 import android.net.MacAddress;
88 import android.net.Network;
89 import android.net.NetworkAgent;
90 import android.net.NetworkAgentConfig;
91 import android.net.NetworkCapabilities;
92 import android.net.NetworkInfo;
93 import android.net.NetworkProvider;
94 import android.net.NetworkSpecifier;
95 import android.net.StaticIpConfiguration;
96 import android.net.Uri;
97 import android.net.ip.IIpClient;
98 import android.net.ip.IpClientCallbacks;
99 import android.net.vcn.VcnManager;
100 import android.net.vcn.VcnNetworkPolicyResult;
101 import android.net.wifi.IActionListener;
102 import android.net.wifi.ScanResult;
103 import android.net.wifi.SupplicantState;
104 import android.net.wifi.WifiConfiguration;
105 import android.net.wifi.WifiConfiguration.KeyMgmt;
106 import android.net.wifi.WifiEnterpriseConfig;
107 import android.net.wifi.WifiInfo;
108 import android.net.wifi.WifiManager;
109 import android.net.wifi.WifiNetworkAgentSpecifier;
110 import android.net.wifi.WifiNetworkSpecifier;
111 import android.net.wifi.WifiSsid;
112 import android.net.wifi.hotspot2.IProvisioningCallback;
113 import android.net.wifi.hotspot2.OsuProvider;
114 import android.net.wifi.nl80211.WifiNl80211Manager;
115 import android.net.wifi.p2p.WifiP2pManager;
116 import android.os.BatteryStatsManager;
117 import android.os.Binder;
118 import android.os.Bundle;
119 import android.os.Handler;
120 import android.os.HandlerThread;
121 import android.os.Looper;
122 import android.os.Message;
123 import android.os.Messenger;
124 import android.os.PowerManager;
125 import android.os.Process;
126 import android.os.test.TestLooper;
127 import android.provider.Settings;
128 import android.telephony.TelephonyManager;
129 import android.test.mock.MockContentProvider;
130 import android.test.mock.MockContentResolver;
131 import android.util.Log;
132 import android.util.Pair;
133 
134 import androidx.test.filters.SmallTest;
135 
136 import com.android.dx.mockito.inline.extended.ExtendedMockito;
137 import com.android.internal.util.AsyncChannel;
138 import com.android.internal.util.IState;
139 import com.android.internal.util.StateMachine;
140 import com.android.modules.utils.build.SdkLevel;
141 import com.android.server.wifi.ClientMode.LinkProbeCallback;
142 import com.android.server.wifi.ClientModeManagerBroadcastQueue.QueuedBroadcast;
143 import com.android.server.wifi.WifiNative.ConnectionCapabilities;
144 import com.android.server.wifi.WifiScoreCard.PerNetwork;
145 import com.android.server.wifi.hotspot2.NetworkDetail;
146 import com.android.server.wifi.hotspot2.PasspointManager;
147 import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil;
148 import com.android.server.wifi.hotspot2.WnmData;
149 import com.android.server.wifi.proto.nano.WifiMetricsProto;
150 import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent;
151 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent;
152 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats;
153 import com.android.server.wifi.util.ActionListenerWrapper;
154 import com.android.server.wifi.util.NativeUtil;
155 import com.android.server.wifi.util.RssiUtilTest;
156 import com.android.server.wifi.util.ScanResultUtil;
157 import com.android.server.wifi.util.WifiPermissionsUtil;
158 import com.android.wifi.resources.R;
159 
160 import org.junit.After;
161 import org.junit.Before;
162 import org.junit.Test;
163 import org.mockito.ArgumentCaptor;
164 import org.mockito.ArgumentMatcher;
165 import org.mockito.Captor;
166 import org.mockito.InOrder;
167 import org.mockito.Mock;
168 import org.mockito.MockitoAnnotations;
169 import org.mockito.MockitoSession;
170 import org.mockito.quality.Strictness;
171 
172 import java.io.ByteArrayOutputStream;
173 import java.io.FileDescriptor;
174 import java.io.PrintWriter;
175 import java.io.StringWriter;
176 import java.lang.reflect.Field;
177 import java.lang.reflect.InvocationTargetException;
178 import java.lang.reflect.Method;
179 import java.net.URL;
180 import java.nio.charset.StandardCharsets;
181 import java.util.ArrayList;
182 import java.util.Arrays;
183 import java.util.Collections;
184 import java.util.Random;
185 import java.util.Set;
186 import java.util.concurrent.CountDownLatch;
187 import java.util.function.Consumer;
188 
189 /**
190  * Unit tests for {@link com.android.server.wifi.ClientModeImpl}.
191  */
192 @SmallTest
193 public class ClientModeImplTest extends WifiBaseTest {
194     public static final String TAG = "ClientModeImplTest";
195 
196     private static final int MANAGED_PROFILE_UID = 1100000;
197     private static final int OTHER_USER_UID = 1200000;
198     private static final int LOG_REC_LIMIT_IN_VERBOSE_MODE =
199             (ActivityManager.isLowRamDeviceStatic()
200                     ? ClientModeImpl.NUM_LOG_RECS_VERBOSE_LOW_MEMORY
201                     : ClientModeImpl.NUM_LOG_RECS_VERBOSE);
202     private static final int FRAMEWORK_NETWORK_ID = 0;
203     private static final int PASSPOINT_NETWORK_ID = 1;
204     private static final int OTHER_NETWORK_ID = 47;
205     private static final int TEST_RSSI = -54;
206     private static final int TEST_NETWORK_ID = 54;
207     private static final int WPS_SUPPLICANT_NETWORK_ID = 5;
208     private static final int WPS_FRAMEWORK_NETWORK_ID = 10;
209     private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
210     private static final String OP_PACKAGE_NAME = "com.xxx";
211     private static final int TEST_UID = Process.SYSTEM_UID + 1000;
212     private static final MacAddress TEST_GLOBAL_MAC_ADDRESS =
213             MacAddress.fromString("10:22:34:56:78:92");
214     private static final MacAddress TEST_LOCAL_MAC_ADDRESS =
215             MacAddress.fromString("2a:53:43:c3:56:21");
216     private static final MacAddress TEST_DEFAULT_MAC_ADDRESS =
217             MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
218 
219     // NetworkAgent creates threshold ranges with Integers
220     private static final int RSSI_THRESHOLD_MAX = -30;
221     private static final int RSSI_THRESHOLD_MIN = -76;
222     // Threshold breach callbacks are called with bytes
223     private static final byte RSSI_THRESHOLD_BREACH_MIN = -80;
224     private static final byte RSSI_THRESHOLD_BREACH_MAX = -20;
225 
226     private static final int DATA_SUBID = 1;
227     private static final int CARRIER_ID_1 = 100;
228 
229     private static final long TEST_BSSID = 0x112233445566L;
230     private static final int TEST_DELAY_IN_SECONDS = 300;
231 
232     private static final int DEFINED_ERROR_CODE = 32764;
233     private static final String TEST_TERMS_AND_CONDITIONS_URL =
234             "https://policies.google.com/terms?hl=en-US";
235     private static final String VENUE_URL =
236             "https://www.android.com/android-11/";
237 
238     private long mBinderToken;
239     private MockitoSession mSession;
240     private TestNetworkParams mTestNetworkParams = new TestNetworkParams();
241 
242     /**
243      * Helper class for setting the default parameters of the WifiConfiguration that gets used
244      * in connect().
245      */
246     class TestNetworkParams {
247         public boolean hasEverConnected = false;
248     }
249 
mockWithInterfaces(Class<T> class1, Class<?>... interfaces)250     private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) {
251         return mock(class1, withSettings().extraInterfaces(interfaces));
252     }
253 
enableDebugLogs()254     private void enableDebugLogs() {
255         mCmi.enableVerboseLogging(true);
256     }
257 
getFrameworkFacade()258     private FrameworkFacade getFrameworkFacade() throws Exception {
259         FrameworkFacade facade = mock(FrameworkFacade.class);
260 
261         doAnswer(new AnswerWithArguments() {
262             public void answer(
263                     Context context, String ifname, IpClientCallbacks callback) {
264                 mIpClientCallback = callback;
265                 callback.onIpClientCreated(mIpClient);
266             }
267         }).when(facade).makeIpClient(any(), anyString(), any());
268 
269         return facade;
270     }
271 
getContext()272     private Context getContext() throws Exception {
273         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
274 
275         Context context = mock(Context.class);
276         when(context.getPackageManager()).thenReturn(mPackageManager);
277 
278         MockContentResolver mockContentResolver = new MockContentResolver();
279         mockContentResolver.addProvider(Settings.AUTHORITY,
280                 new MockContentProvider(context) {
281                     @Override
282                     public Bundle call(String method, String arg, Bundle extras) {
283                         return new Bundle();
284                     }
285                 });
286         when(context.getContentResolver()).thenReturn(mockContentResolver);
287 
288         when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
289         when(context.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
290         when(mPowerManager.isInteractive()).thenReturn(true);
291         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(
292                 mock(PowerManager.WakeLock.class));
293 
294         mAlarmManager = new TestAlarmManager();
295         when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
296                 mAlarmManager.getAlarmManager());
297 
298         when(context.getOpPackageName()).thenReturn(OP_PACKAGE_NAME);
299 
300         when(context.getSystemService(ActivityManager.class)).thenReturn(
301                 mock(ActivityManager.class));
302 
303         WifiP2pManager p2pm = mock(WifiP2pManager.class);
304         when(context.getSystemService(WifiP2pManager.class)).thenReturn(p2pm);
305         final CountDownLatch untilDone = new CountDownLatch(1);
306         mP2pThread = new HandlerThread("WifiP2pMockThread") {
307             @Override
308             protected void onLooperPrepared() {
309                 untilDone.countDown();
310             }
311         };
312         mP2pThread.start();
313         untilDone.await();
314         Handler handler = new Handler(mP2pThread.getLooper());
315         when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler));
316 
317         return context;
318     }
319 
getMockResources()320     private MockResources getMockResources() {
321         MockResources resources = new MockResources();
322         return resources;
323     }
324 
getCurrentState()325     private IState getCurrentState() throws
326             NoSuchMethodException, InvocationTargetException, IllegalAccessException {
327         Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
328         method.setAccessible(true);
329         return (IState) method.invoke(mCmi);
330     }
331 
getCmiHandlerThread(ClientModeImpl cmi)332     private static HandlerThread getCmiHandlerThread(ClientModeImpl cmi) throws
333             NoSuchFieldException, InvocationTargetException, IllegalAccessException {
334         Field field = StateMachine.class.getDeclaredField("mSmThread");
335         field.setAccessible(true);
336         return (HandlerThread) field.get(cmi);
337     }
338 
stopLooper(final Looper looper)339     private static void stopLooper(final Looper looper) throws Exception {
340         new Handler(looper).post(new Runnable() {
341             @Override
342             public void run() {
343                 looper.quitSafely();
344             }
345         });
346     }
347 
dumpState()348     private void dumpState() {
349         ByteArrayOutputStream stream = new ByteArrayOutputStream();
350         PrintWriter writer = new PrintWriter(stream);
351         mCmi.dump(null, writer, null);
352         writer.flush();
353         Log.d(TAG, "ClientModeImpl state -" + stream.toString());
354     }
355 
getGoogleGuestScanDetail(int rssi, String bssid, int freq)356     private static ScanDetail getGoogleGuestScanDetail(int rssi, String bssid, int freq) {
357         ScanResult.InformationElement[] ie = new ScanResult.InformationElement[1];
358         ie[0] = ScanResults.generateSsidIe(TEST_SSID);
359         NetworkDetail nd = new NetworkDetail(TEST_BSSID_STR, ie, new ArrayList<String>(), sFreq);
360         ScanDetail detail = new ScanDetail(nd, TEST_WIFI_SSID, bssid, "", rssi, freq,
361                 Long.MAX_VALUE, /* needed so that scan results aren't rejected because
362                                    there older than scan start */
363                 ie, new ArrayList<String>(), ScanResults.generateIERawDatafromScanResultIE(ie));
364 
365         return detail;
366     }
367 
getMockScanResults()368     private ArrayList<ScanDetail> getMockScanResults() {
369         ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
370         ArrayList<ScanDetail> list = sr.getScanDetailArrayList();
371 
372         list.add(getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
373         return list;
374     }
375 
injectDhcpSuccess(DhcpResultsParcelable dhcpResults)376     private void injectDhcpSuccess(DhcpResultsParcelable dhcpResults) {
377         mIpClientCallback.onNewDhcpResults(dhcpResults);
378         mIpClientCallback.onProvisioningSuccess(new LinkProperties());
379     }
380 
injectDhcpFailure()381     private void injectDhcpFailure() {
382         mIpClientCallback.onNewDhcpResults((DhcpResultsParcelable) null);
383         mIpClientCallback.onProvisioningFailure(new LinkProperties());
384     }
385 
386     static final String   TEST_SSID = "\"GoogleGuest\"";
387     static final String   SSID_NO_QUOTE = TEST_SSID.replace("\"", "");
388     static final WifiSsid TEST_WIFI_SSID = WifiSsid.createFromAsciiEncoded(SSID_NO_QUOTE);
389     static final String   TEST_SSID1 = "\"RandomSsid1\"";
390     static final String   SSID_NO_QUOTE1 = TEST_SSID1.replace("\"", "");
391     static final WifiSsid TEST_WIFI_SSID1 = WifiSsid.createFromAsciiEncoded(SSID_NO_QUOTE1);
392     static final String   TEST_BSSID_STR = "01:02:03:04:05:06";
393     static final String   TEST_BSSID_STR1 = "02:01:04:03:06:05";
394     static final int      sFreq = 2437;
395     static final int      sFreq1 = 5240;
396     static final String   WIFI_IFACE_NAME = "mockWlan";
397     static final String sFilsSsid = "FILS-AP";
398 
399     ClientModeImpl mCmi;
400     HandlerThread mWifiCoreThread;
401     HandlerThread mP2pThread;
402     HandlerThread mSyncThread;
403     TestAlarmManager mAlarmManager;
404     MockWifiMonitor mWifiMonitor;
405     TestLooper mLooper;
406     Context mContext;
407     MockResources mResources;
408     FrameworkFacade mFrameworkFacade;
409     IpClientCallbacks mIpClientCallback;
410     OsuProvider mOsuProvider;
411     WifiConfiguration mConnectedNetwork;
412     ExtendedWifiInfo mWifiInfo;
413     ConnectionCapabilities mConnectionCapabilities = new ConnectionCapabilities();
414 
415     @Mock WifiNetworkAgent mWifiNetworkAgent;
416     @Mock SupplicantStateTracker mSupplicantStateTracker;
417     @Mock WifiMetrics mWifiMetrics;
418     @Mock WifiInjector mWifiInjector;
419     @Mock WifiLastResortWatchdog mWifiLastResortWatchdog;
420     @Mock WifiBlocklistMonitor mWifiBlocklistMonitor;
421     @Mock WifiConfigManager mWifiConfigManager;
422     @Mock WifiNative mWifiNative;
423     @Mock WifiScoreCard mWifiScoreCard;
424     @Mock PerNetwork mPerNetwork;
425     @Mock WifiScoreCard.NetworkConnectionStats mPerNetworkRecentStats;
426     @Mock WifiHealthMonitor mWifiHealthMonitor;
427     @Mock WifiTrafficPoller mWifiTrafficPoller;
428     @Mock WifiConnectivityManager mWifiConnectivityManager;
429     @Mock WifiStateTracker mWifiStateTracker;
430     @Mock PasspointManager mPasspointManager;
431     @Mock WifiPermissionsUtil mWifiPermissionsUtil;
432     @Mock IIpClient mIpClient;
433     @Mock TelephonyManager mTelephonyManager;
434     @Mock TelephonyManager mDataTelephonyManager;
435     @Mock WrongPasswordNotifier mWrongPasswordNotifier;
436     @Mock Clock mClock;
437     @Mock ScanDetailCache mScanDetailCache;
438     @Mock WifiDiagnostics mWifiDiagnostics;
439     @Mock IProvisioningCallback mProvisioningCallback;
440     @Mock WakeupController mWakeupController;
441     @Mock WifiDataStall mWifiDataStall;
442     @Mock WifiNetworkFactory mWifiNetworkFactory;
443     @Mock UntrustedWifiNetworkFactory mUntrustedWifiNetworkFactory;
444     @Mock OemWifiNetworkFactory mOemWifiNetworkFactory;
445     @Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
446     @Mock LinkProbeManager mLinkProbeManager;
447     @Mock PackageManager mPackageManager;
448     @Mock WifiLockManager mWifiLockManager;
449     @Mock AsyncChannel mNullAsyncChannel;
450     @Mock BatteryStatsManager mBatteryStatsManager;
451     @Mock MboOceController mMboOceController;
452     @Mock ConnectionFailureNotifier mConnectionFailureNotifier;
453     @Mock EapFailureNotifier mEapFailureNotifier;
454     @Mock SimRequiredNotifier mSimRequiredNotifier;
455     @Mock ThroughputPredictor mThroughputPredictor;
456     @Mock ScanRequestProxy mScanRequestProxy;
457     @Mock DeviceConfigFacade mDeviceConfigFacade;
458     @Mock Network mNetwork;
459     @Mock ConcreteClientModeManager mClientModeManager;
460     @Mock WifiScoreReport mWifiScoreReport;
461     @Mock PowerManager mPowerManager;
462     @Mock WifiP2pConnection mWifiP2pConnection;
463     @Mock WifiGlobals mWifiGlobals;
464     @Mock LinkProbeCallback mLinkProbeCallback;
465     @Mock ClientModeImplMonitor mCmiMonitor;
466     @Mock ClientModeManagerBroadcastQueue mBroadcastQueue;
467     @Mock WifiNetworkSelector mWifiNetworkSelector;
468     @Mock ActiveModeWarden mActiveModeWarden;
469     @Mock ClientModeManager mPrimaryClientModeManager;
470     @Mock WifiSettingsConfigStore mSettingsConfigStore;
471     @Mock Uri mMockUri;
472     @Mock WifiCarrierInfoManager mWifiCarrierInfoManager;
473 
474     @Captor ArgumentCaptor<WifiConfigManager.OnNetworkUpdateListener> mConfigUpdateListenerCaptor;
475     @Captor ArgumentCaptor<WifiNetworkAgent.Callback> mWifiNetworkAgentCallbackCaptor;
476     @Captor ArgumentCaptor<WifiCarrierInfoManager.OnCarrierOffloadDisabledListener>
477             mOffloadDisabledListenerArgumentCaptor = ArgumentCaptor.forClass(
478                     WifiCarrierInfoManager.OnCarrierOffloadDisabledListener.class);
479     @Captor ArgumentCaptor<BroadcastReceiver> mScreenStateBroadcastReceiverCaptor;
480 
setUpWifiNative()481     private void setUpWifiNative() throws Exception {
482         when(mWifiNative.getStaFactoryMacAddress(WIFI_IFACE_NAME)).thenReturn(
483                 TEST_GLOBAL_MAC_ADDRESS);
484         doAnswer(new AnswerWithArguments() {
485             public void answer(WifiSettingsConfigStore.Key<String> key, Object macAddress) {
486                 when(mSettingsConfigStore.get(WIFI_STA_FACTORY_MAC_ADDRESS))
487                         .thenReturn((String) macAddress);
488             }
489         }).when(mSettingsConfigStore).put(eq(WIFI_STA_FACTORY_MAC_ADDRESS), any(String.class));
490         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
491                 .thenReturn(TEST_GLOBAL_MAC_ADDRESS.toString());
492         ConnectionCapabilities cap = new ConnectionCapabilities();
493         cap.wifiStandard = ScanResult.WIFI_STANDARD_11AC;
494         when(mWifiNative.getConnectionCapabilities(WIFI_IFACE_NAME))
495                 .thenReturn(mConnectionCapabilities);
496         when(mWifiNative.setStaMacAddress(eq(WIFI_IFACE_NAME), anyObject()))
497                 .then(new AnswerWithArguments() {
498                     public boolean answer(String iface, MacAddress mac) {
499                         when(mWifiNative.getMacAddress(iface)).thenReturn(mac.toString());
500                         return true;
501                     }
502                 });
503         when(mWifiNative.connectToNetwork(any(), any())).thenReturn(true);
504     }
505 
506     /** Reset verify() counters on WifiNative, and restore when() mocks on mWifiNative */
resetWifiNative()507     private void resetWifiNative() throws Exception {
508         reset(mWifiNative);
509         setUpWifiNative();
510     }
511 
512     @Before
setUp()513     public void setUp() throws Exception {
514         Log.d(TAG, "Setting up ...");
515 
516         // Ensure looper exists
517         mLooper = new TestLooper();
518 
519         MockitoAnnotations.initMocks(this);
520 
521         /** uncomment this to enable logs from ClientModeImpls */
522         // enableDebugLogs();
523         mWifiMonitor = spy(new MockWifiMonitor());
524         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager);
525         when(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName(any(), any()))
526                 .thenReturn(Pair.create(Process.INVALID_UID, ""));
527         setUpWifiNative();
528         doAnswer(new AnswerWithArguments() {
529             public MacAddress answer(
530                     WifiConfiguration config) {
531                 return config.getRandomizedMacAddress();
532             }
533         }).when(mWifiConfigManager).getRandomizedMacAndUpdateIfNeeded(any());
534 
535         mTestNetworkParams = new TestNetworkParams();
536         when(mWifiNetworkFactory.hasConnectionRequests()).thenReturn(true);
537         when(mUntrustedWifiNetworkFactory.hasConnectionRequests()).thenReturn(true);
538         when(mOemWifiNetworkFactory.hasConnectionRequests()).thenReturn(true);
539 
540         mFrameworkFacade = getFrameworkFacade();
541         mContext = getContext();
542         mWifiInfo = new ExtendedWifiInfo(mWifiGlobals, WIFI_IFACE_NAME);
543 
544         when(mWifiGlobals.isConnectedMacRandomizationEnabled()).thenReturn(true);
545         mResources = getMockResources();
546         mResources.setIntArray(R.array.config_wifiRssiLevelThresholds,
547                 RssiUtilTest.RSSI_THRESHOLDS);
548         mResources.setInteger(R.integer.config_wifiLinkBandwidthUpdateThresholdPercent, 25);
549         mResources.setInteger(R.integer.config_wifiClientModeImplNumLogRecs, 100);
550         mResources.setBoolean(R.bool.config_wifiEnableLinkedNetworkRoaming, true);
551         when(mContext.getResources()).thenReturn(mResources);
552 
553         when(mWifiGlobals.getPollRssiIntervalMillis()).thenReturn(3000);
554         when(mWifiGlobals.getIpReachabilityDisconnectEnabled()).thenReturn(true);
555 
556         when(mFrameworkFacade.getIntegerSetting(mContext,
557                 Settings.Global.WIFI_FREQUENCY_BAND,
558                 WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn(
559                 WifiManager.WIFI_FREQUENCY_BAND_AUTO);
560         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
561         doAnswer(inv -> {
562             mIpClientCallback.onQuit();
563             return null;
564         }).when(mIpClient).shutdown();
565         when(mWifiNetworkAgent.getNetwork()).thenReturn(mNetwork);
566 
567         // static mocking
568         mSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
569                 .mockStatic(WifiInjector.class, withSettings().lenient())
570                 .spyStatic(MacAddress.class)
571                 .startMocking();
572         when(WifiInjector.getInstance()).thenReturn(mWifiInjector);
573 
574         when(mWifiInjector.getActiveModeWarden()).thenReturn(mActiveModeWarden);
575         when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(mPrimaryClientModeManager);
576         when(mPrimaryClientModeManager.getSupportedFeatures()).thenReturn(
577                 WifiManager.WIFI_FEATURE_WPA3_SAE | WifiManager.WIFI_FEATURE_OWE);
578         when(mWifiInjector.getWifiGlobals()).thenReturn(mWifiGlobals);
579         when(mWifiGlobals.isWpa3SaeUpgradeEnabled()).thenReturn(true);
580         when(mWifiGlobals.isOweUpgradeEnabled()).thenReturn(true);
581         when(mWifiGlobals.getClientModeImplNumLogRecs()).thenReturn(100);
582         when(mWifiInjector.makeWifiNetworkAgent(any(), any(), any(), any(), any()))
583                 .thenAnswer(new AnswerWithArguments() {
584                     public WifiNetworkAgent answer(
585                             @NonNull NetworkCapabilities nc,
586                             @NonNull LinkProperties linkProperties,
587                             @NonNull NetworkAgentConfig naConfig,
588                             @Nullable NetworkProvider provider,
589                             @NonNull WifiNetworkAgent.Callback callback) {
590                         when(mWifiNetworkAgent.getCallback()).thenReturn(callback);
591                         return mWifiNetworkAgent;
592                     }
593                 });
594         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
595 
596         initializeCmi();
597         // Retrieve factory MAC address on first bootup.
598         verify(mWifiNative).getStaFactoryMacAddress(WIFI_IFACE_NAME);
599 
600         mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
601         mConnectedNetwork = spy(WifiConfigurationTestUtil.createOpenNetwork());
602         when(mNullAsyncChannel.sendMessageSynchronously(any())).thenReturn(null);
603         when(mWifiScoreCard.getL2KeyAndGroupHint(any())).thenReturn(new Pair<>(null, null));
604         when(mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()).thenReturn(true);
605         when(mDeviceConfigFacade.isAbnormalConnectionFailureBugreportEnabled()).thenReturn(true);
606         when(mDeviceConfigFacade.isOverlappingConnectionBugreportEnabled()).thenReturn(true);
607         when(mDeviceConfigFacade.getOverlappingConnectionDurationThresholdMs()).thenReturn(
608                 DeviceConfigFacade.DEFAULT_OVERLAPPING_CONNECTION_DURATION_THRESHOLD_MS);
609         when(mWifiScoreCard.detectAbnormalConnectionFailure(anyString()))
610                 .thenReturn(WifiHealthMonitor.REASON_NO_FAILURE);
611         when(mWifiScoreCard.detectAbnormalDisconnection(any()))
612                 .thenReturn(WifiHealthMonitor.REASON_NO_FAILURE);
613         when(mPerNetwork.getRecentStats()).thenReturn(mPerNetworkRecentStats);
614         when(mWifiScoreCard.lookupNetwork(any())).thenReturn(mPerNetwork);
615         when(mThroughputPredictor.predictMaxTxThroughput(any())).thenReturn(90);
616         when(mThroughputPredictor.predictMaxRxThroughput(any())).thenReturn(80);
617 
618         doAnswer(new AnswerWithArguments() {
619             public void answer(boolean shouldReduceNetworkScore) {
620                 mCmi.setShouldReduceNetworkScore(shouldReduceNetworkScore);
621             }
622         }).when(mClientModeManager).setShouldReduceNetworkScore(anyBoolean());
623         doAnswer(new AnswerWithArguments() {
624             public void answer(ClientModeManager manager, QueuedBroadcast broadcast) {
625                 broadcast.send();
626             }
627         }).when(mBroadcastQueue).queueOrSendBroadcast(any(), any());
628     }
629 
registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger, Handler wrappedHandler)630     private void registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger,
631             Handler wrappedHandler) {
632         final AsyncChannel channel = new AsyncChannel();
633         Handler handler = new Handler(mLooper.getLooper()) {
634             @Override
635             public void handleMessage(Message msg) {
636                 switch (msg.what) {
637                     case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
638                         if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
639                             consumer.accept(channel);
640                         } else {
641                             Log.d(TAG, "Failed to connect Command channel " + this);
642                         }
643                         break;
644                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
645                         Log.d(TAG, "Command channel disconnected " + this);
646                         break;
647                     case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
648                         Log.d(TAG, "Command channel fully connected " + this);
649                         break;
650                     default:
651                         if (wrappedHandler != null) {
652                             wrappedHandler.handleMessage(msg);
653                         }
654                         break;
655                 }
656             }
657         };
658 
659         channel.connect(mContext, handler, messenger);
660         mLooper.dispatchAll();
661     }
662 
registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger)663     private void registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger) {
664         registerAsyncChannel(consumer, messenger, null /* wrappedHandler */);
665     }
666 
initializeCmi()667     private void initializeCmi() throws Exception {
668         mCmi = new ClientModeImpl(mContext, mWifiMetrics, mClock, mWifiScoreCard, mWifiStateTracker,
669                 mWifiPermissionsUtil, mWifiConfigManager, mPasspointManager,
670                 mWifiMonitor, mWifiDiagnostics, mWifiDataStall,
671                 new ScoringParams(), new WifiThreadRunner(new Handler(mLooper.getLooper())),
672                 mWifiNetworkSuggestionsManager, mWifiHealthMonitor, mThroughputPredictor,
673                 mDeviceConfigFacade, mScanRequestProxy, mWifiInfo, mWifiConnectivityManager,
674                 mWifiBlocklistMonitor, mConnectionFailureNotifier,
675                 WifiInjector.REGULAR_NETWORK_CAPABILITIES_FILTER, mWifiNetworkFactory,
676                 mUntrustedWifiNetworkFactory, mOemWifiNetworkFactory,
677                 mWifiLastResortWatchdog, mWakeupController,
678                 mWifiLockManager, mFrameworkFacade, mLooper.getLooper(),
679                 mWifiNative, mWrongPasswordNotifier, mWifiTrafficPoller, mLinkProbeManager,
680                 1, mBatteryStatsManager, mSupplicantStateTracker, mMboOceController,
681                 mWifiCarrierInfoManager, mEapFailureNotifier, mSimRequiredNotifier,
682                 mWifiScoreReport, mWifiP2pConnection, mWifiGlobals,
683                 WIFI_IFACE_NAME, mClientModeManager, mCmiMonitor, mBroadcastQueue,
684                 mWifiNetworkSelector, mTelephonyManager, mWifiInjector, mSettingsConfigStore,
685                 false);
686 
687         mWifiCoreThread = getCmiHandlerThread(mCmi);
688 
689         mBinderToken = Binder.clearCallingIdentity();
690 
691         verify(mWifiConfigManager, atLeastOnce()).addOnNetworkUpdateListener(
692                 mConfigUpdateListenerCaptor.capture());
693         assertNotNull(mConfigUpdateListenerCaptor.getValue());
694 
695         verify(mWifiCarrierInfoManager, atLeastOnce()).addOnCarrierOffloadDisabledListener(
696                 mOffloadDisabledListenerArgumentCaptor.capture());
697         assertNotNull(mOffloadDisabledListenerArgumentCaptor.getValue());
698 
699         mCmi.enableVerboseLogging(true);
700         mLooper.dispatchAll();
701 
702         verify(mWifiLastResortWatchdog, atLeastOnce()).clearAllFailureCounts();
703         assertEquals("DisconnectedState", getCurrentState().getName());
704 
705         verify(mContext, atLeastOnce()).registerReceiver(
706                 mScreenStateBroadcastReceiverCaptor.capture(),
707                 argThat(f -> f.hasAction(ACTION_SCREEN_ON) && f.hasAction(ACTION_SCREEN_OFF)));
708     }
709 
710     @After
cleanUp()711     public void cleanUp() throws Exception {
712         Binder.restoreCallingIdentity(mBinderToken);
713 
714         if (mSyncThread != null) stopLooper(mSyncThread.getLooper());
715         if (mWifiCoreThread != null) stopLooper(mWifiCoreThread.getLooper());
716         if (mP2pThread != null) stopLooper(mP2pThread.getLooper());
717 
718         mWifiCoreThread = null;
719         mP2pThread = null;
720         mSyncThread = null;
721         mCmi = null;
722         if (mSession != null) {
723             mSession.finishMocking();
724         }
725     }
726 
727     /**
728      *  Test that mode changes accurately reflect the value for isWifiEnabled.
729      */
730     @Test
checkIsWifiEnabledForModeChanges()731     public void checkIsWifiEnabledForModeChanges() throws Exception {
732         // now disable client mode and verify the reported wifi state
733         mCmi.stop();
734         mLooper.dispatchAll();
735         verify(mContext, never())
736                 .sendStickyBroadcastAsUser(argThat(new WifiEnablingStateIntentMatcher()), any());
737     }
738 
739     private static class WifiEnablingStateIntentMatcher implements ArgumentMatcher<Intent> {
740         @Override
matches(Intent intent)741         public boolean matches(Intent intent) {
742             return WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())
743                     && WifiManager.WIFI_STATE_ENABLING
744                             == intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
745                                     WifiManager.WIFI_STATE_DISABLED);
746         }
747     }
748 
749     private class NetworkStateChangedIntentMatcher implements ArgumentMatcher<Intent> {
750         private final NetworkInfo.DetailedState mState;
NetworkStateChangedIntentMatcher(NetworkInfo.DetailedState state)751         NetworkStateChangedIntentMatcher(NetworkInfo.DetailedState state) {
752             mState = state;
753         }
754         @Override
matches(Intent intent)755         public boolean matches(Intent intent) {
756             if (WifiManager.NETWORK_STATE_CHANGED_ACTION != intent.getAction()) {
757                 // not the correct type
758                 return false;
759             }
760             NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
761             return networkInfo.getDetailedState() == mState;
762         }
763     }
764 
canSaveNetworkConfig()765     private void canSaveNetworkConfig() throws Exception {
766         IActionListener connectActionListener = mock(IActionListener.class);
767         mCmi.saveNetwork(
768                 new NetworkUpdateResult(TEST_NETWORK_ID),
769                 new ActionListenerWrapper(connectActionListener),
770                 Binder.getCallingUid());
771         mLooper.dispatchAll();
772         verify(connectActionListener).onSuccess();
773     }
774 
775     /**
776      * Verifies that configs can be saved when in client mode.
777      */
778     @Test
canSaveNetworkConfigInClientMode()779     public void canSaveNetworkConfigInClientMode() throws Exception {
780         canSaveNetworkConfig();
781     }
782 
createTestNetwork(boolean isHidden)783     private WifiConfiguration createTestNetwork(boolean isHidden) {
784         WifiConfiguration config = new WifiConfiguration();
785         config.networkId = FRAMEWORK_NETWORK_ID;
786         config.SSID = TEST_SSID;
787         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
788         config.hiddenSSID = isHidden;
789         return config;
790     }
791 
initializeMocksForAddedNetwork(boolean isHidden)792     private void initializeMocksForAddedNetwork(boolean isHidden) throws Exception {
793         WifiConfiguration config = createTestNetwork(isHidden);
794 
795         when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(Arrays.asList(config));
796         when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config);
797         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(0)).thenReturn(config);
798     }
799 
initializeAndAddNetworkAndVerifySuccess()800     private void initializeAndAddNetworkAndVerifySuccess() throws Exception {
801         initializeAndAddNetworkAndVerifySuccess(false);
802     }
803 
initializeAndAddNetworkAndVerifySuccess(boolean isHidden)804     private void initializeAndAddNetworkAndVerifySuccess(boolean isHidden) throws Exception {
805         initializeMocksForAddedNetwork(isHidden);
806     }
807 
setupAndStartConnectSequence(WifiConfiguration config)808     private void setupAndStartConnectSequence(WifiConfiguration config) throws Exception {
809         when(mWifiConfigManager.getConfiguredNetwork(eq(config.networkId)))
810                 .thenReturn(config);
811         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(
812                 eq(config.networkId))).thenReturn(config);
813 
814         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
815 
816         IActionListener connectActionListener = mock(IActionListener.class);
817         mCmi.connectNetwork(
818                 new NetworkUpdateResult(config.networkId),
819                 new ActionListenerWrapper(connectActionListener),
820                 Binder.getCallingUid());
821         mLooper.dispatchAll();
822         verify(connectActionListener).onSuccess();
823     }
824 
validateSuccessfulConnectSequence(WifiConfiguration config)825     private void validateSuccessfulConnectSequence(WifiConfiguration config) {
826         verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
827         verify(mWifiConfigManager).getConfiguredNetworkWithoutMasking(eq(config.networkId));
828         verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
829         verify(mCmiMonitor).onConnectionStart(mClientModeManager);
830         assertEquals("L2ConnectingState", mCmi.getCurrentState().getName());
831     }
832 
validateFailureConnectSequence(WifiConfiguration config)833     private void validateFailureConnectSequence(WifiConfiguration config) {
834         verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
835         verify(mWifiConfigManager, never())
836                 .getConfiguredNetworkWithoutMasking(eq(config.networkId));
837         verify(mWifiNative, never()).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
838     }
839 
840     /**
841      * Tests the network connection initiation sequence with the default network request pending
842      * from WifiNetworkFactory.
843      * This simulates the connect sequence using the public
844      * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we invoke
845      * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
846      */
847     @Test
triggerConnect()848     public void triggerConnect() throws Exception {
849         WifiConfiguration config = mConnectedNetwork;
850         config.networkId = FRAMEWORK_NETWORK_ID;
851         config.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS);
852         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
853         config.getNetworkSelectionStatus().setHasEverConnected(mTestNetworkParams.hasEverConnected);
854         assertEquals(null, config.getNetworkSelectionStatus().getCandidateSecurityParams());
855         setupAndStartConnectSequence(config);
856         validateSuccessfulConnectSequence(config);
857         assertEquals(config.getSecurityParamsList().stream()
858                         .filter(WifiConfigurationUtil::isSecurityParamsValid)
859                         .findFirst().orElse(null),
860                 config.getNetworkSelectionStatus().getCandidateSecurityParams());
861     }
862 
863     /**
864      * Tests the network connection initiation sequence with the default network request pending
865      * from WifiNetworkFactory.
866      * This simulates the connect sequence using the public
867      * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we invoke
868      * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
869      */
870     @Test
triggerConnectFromNonSettingsApp()871     public void triggerConnectFromNonSettingsApp() throws Exception {
872         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
873         config.networkId = FRAMEWORK_NETWORK_ID;
874         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(Process.myUid()))
875                 .thenReturn(false);
876         setupAndStartConnectSequence(config);
877         verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
878         verify(mWifiConfigManager).getConfiguredNetworkWithoutMasking(eq(config.networkId));
879         verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
880     }
881 
882     /**
883      * Tests the network connection initiation sequence with no network request pending from
884      * from WifiNetworkFactory.
885      * This simulates the connect sequence using the public
886      * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we don't invoke
887      * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
888      */
889     @Test
triggerConnectWithNoNetworkRequest()890     public void triggerConnectWithNoNetworkRequest() throws Exception {
891         // Remove the network requests.
892         when(mWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
893         when(mUntrustedWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
894         when(mOemWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
895 
896         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
897         config.networkId = FRAMEWORK_NETWORK_ID;
898         setupAndStartConnectSequence(config);
899         validateFailureConnectSequence(config);
900     }
901 
902     /**
903      * Tests the entire successful network connection flow.
904      */
905     @Test
testConnect()906     public void testConnect() throws Exception {
907         connect(null);
908     }
909 
connect()910     private void connect() throws Exception {
911         connect(null);
912     }
913 
914     /**
915      * Simulate a connect
916      *
917      * @param wnmDataForTermsAndConditions Use null unless it is required to simulate a terms and
918      *                                     conditions acceptance notification from Passpoint
919      * @throws Exception
920      */
connect(WnmData wnmDataForTermsAndConditions)921     private void connect(WnmData wnmDataForTermsAndConditions) throws Exception {
922         assertNull(mCmi.getConnectingWifiConfiguration());
923         assertNull(mCmi.getConnectedWifiConfiguration());
924 
925         triggerConnect();
926 
927         assertNotNull(mCmi.getConnectingWifiConfiguration());
928         assertNull(mCmi.getConnectedWifiConfiguration());
929 
930         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID);
931         config.carrierId = CARRIER_ID_1;
932         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
933                 .thenReturn(mScanDetailCache);
934 
935         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
936                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
937         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
938                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
939         ScanResult scanResult = new ScanResult(WifiSsid.createFromAsciiEncoded(sFilsSsid),
940                 sFilsSsid, TEST_BSSID_STR, 1245, 0, "", -78, 2412, 1025, 22, 33, 20, 0, 0, true);
941         ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID,
942                 sFilsSsid.getBytes(StandardCharsets.UTF_8));
943         scanResult.informationElements = new ScanResult.InformationElement[]{ie};
944         when(mScanRequestProxy.getScanResult(eq(TEST_BSSID_STR))).thenReturn(scanResult);
945 
946         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
947                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
948                         SupplicantState.ASSOCIATED));
949         mLooper.dispatchAll();
950 
951         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
952                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
953         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
954                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
955         mLooper.dispatchAll();
956 
957         verify(mWifiMetrics).noteFirstL2ConnectionAfterBoot(true);
958 
959         // L2 connected, but not L3 connected yet. So, still "Connecting"...
960         assertNotNull(mCmi.getConnectingWifiConfiguration());
961         assertNull(mCmi.getConnectedWifiConfiguration());
962 
963         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
964                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
965                         SupplicantState.COMPLETED));
966         mLooper.dispatchAll();
967 
968         assertEquals("L3ProvisioningState", getCurrentState().getName());
969         verify(mContext).sendStickyBroadcastAsUser(
970                 argThat(new NetworkStateChangedIntentMatcher(CONNECTING)), any());
971         verify(mContext).sendStickyBroadcastAsUser(
972                 argThat(new NetworkStateChangedIntentMatcher(OBTAINING_IPADDR)), any());
973 
974         if (wnmDataForTermsAndConditions != null) {
975             mCmi.sendMessage(WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT,
976                     0, 0, wnmDataForTermsAndConditions);
977             mLooper.dispatchAll();
978         }
979 
980         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
981         dhcpResults.baseConfiguration = new StaticIpConfiguration();
982         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
983         dhcpResults.baseConfiguration.ipAddress =
984                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
985         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
986         dhcpResults.leaseDuration = 3600;
987 
988         injectDhcpSuccess(dhcpResults);
989         mLooper.dispatchAll();
990 
991         assertNull(mCmi.getConnectingWifiConfiguration());
992         assertNotNull(mCmi.getConnectedWifiConfiguration());
993 
994         // Verify WifiMetrics logging for metered metrics based on DHCP results
995         verify(mWifiMetrics).addMeteredStat(any(), anyBoolean());
996         WifiInfo wifiInfo = mWifiInfo;
997         assertNotNull(wifiInfo);
998         assertEquals(TEST_BSSID_STR, wifiInfo.getBSSID());
999         assertEquals(sFreq, wifiInfo.getFrequency());
1000         assertEquals(TEST_WIFI_SSID, wifiInfo.getWifiSsid());
1001         assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, wifiInfo.getMacAddress());
1002         assertEquals(mConnectedNetwork.getDefaultSecurityParams().getSecurityType(),
1003                 mWifiInfo.getCurrentSecurityType());
1004         if (wifiInfo.isPasspointAp()) {
1005             assertEquals(wifiInfo.getPasspointProviderFriendlyName(),
1006                     WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME);
1007         } else {
1008             assertNull(wifiInfo.getPasspointProviderFriendlyName());
1009         }
1010         assertEquals(Arrays.asList(scanResult.informationElements),
1011                     wifiInfo.getInformationElements());
1012         expectRegisterNetworkAgent((na) -> {
1013             if (!mConnectedNetwork.carrierMerged) {
1014                 assertNull(na.subscriberId);
1015             }
1016         }, (nc) -> {
1017                 if (SdkLevel.isAtLeastS()) {
1018                     WifiInfo wifiInfoFromTi = (WifiInfo) nc.getTransportInfo();
1019                     assertEquals(TEST_BSSID_STR, wifiInfoFromTi.getBSSID());
1020                     assertEquals(sFreq, wifiInfoFromTi.getFrequency());
1021                     assertEquals(TEST_WIFI_SSID, wifiInfoFromTi.getWifiSsid());
1022                     if (wifiInfo.isPasspointAp()) {
1023                         assertEquals(wifiInfoFromTi.getPasspointProviderFriendlyName(),
1024                                 WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME);
1025                     } else {
1026                         assertNull(wifiInfoFromTi.getPasspointProviderFriendlyName());
1027                     }
1028                 }
1029             });
1030         // Ensure the connection stats for the network is updated.
1031         verify(mWifiConfigManager).updateNetworkAfterConnect(eq(FRAMEWORK_NETWORK_ID),
1032                 anyBoolean(), anyInt());
1033         verify(mWifiConfigManager).updateRandomizedMacExpireTime(any(), anyLong());
1034         verify(mContext).sendStickyBroadcastAsUser(
1035                 argThat(new NetworkStateChangedIntentMatcher(CONNECTED)), any());
1036 
1037         // Anonymous Identity is not set.
1038         assertEquals("", mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1039         verify(mWifiStateTracker).updateState(WIFI_IFACE_NAME, WifiStateTracker.CONNECTED);
1040         assertEquals("L3ConnectedState", getCurrentState().getName());
1041         verify(mWifiMetrics).incrementNumOfCarrierWifiConnectionSuccess();
1042         verify(mWifiLockManager).updateWifiClientConnected(mClientModeManager, true);
1043         verify(mWifiNative).getConnectionCapabilities(any());
1044         verify(mThroughputPredictor).predictMaxTxThroughput(any());
1045         verify(mWifiMetrics).setConnectionMaxSupportedLinkSpeedMbps(WIFI_IFACE_NAME, 90, 80);
1046         assertEquals(90, wifiInfo.getMaxSupportedTxLinkSpeedMbps());
1047         verify(mWifiMetrics).noteFirstL3ConnectionAfterBoot(true);
1048     }
1049 
setupEapSimConnection()1050     private void setupEapSimConnection() throws Exception {
1051         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1052                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1053         mConnectedNetwork.carrierId = CARRIER_ID_1;
1054         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1055                 .thenReturn(DATA_SUBID);
1056         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1057         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1058 
1059         triggerConnect();
1060 
1061         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1062                 .thenReturn(mScanDetailCache);
1063         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1064                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1065         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1066                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1067 
1068         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1069                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1070         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1071                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1072         mLooper.dispatchAll();
1073         assertEquals("L3ProvisioningState", getCurrentState().getName());
1074     }
1075 
1076     /**
1077      * Test when a roam occurs simultaneously with another connection attempt.
1078      * The roam's NETWORK_CONNECTION_EVENT should be ignored, only the new network's
1079      * NETWORK_CONNECTION_EVENT should be acted upon.
1080      */
1081     @Test
roamRaceWithConnect()1082     public void roamRaceWithConnect() throws Exception {
1083         connect();
1084 
1085         initializeAndAddNetworkAndVerifySuccess();
1086 
1087         // connect to new network
1088         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
1089         config.networkId = OTHER_NETWORK_ID;
1090         setupAndStartConnectSequence(config);
1091 
1092         // in L2ConnectingState
1093         assertEquals("L2ConnectingState", getCurrentState().getName());
1094 
1095         // send NETWORK_CONNECTION_EVENT for previous network ID
1096         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1097                 new NetworkConnectionEventInfo(
1098                         FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR, false));
1099         mLooper.dispatchAll();
1100 
1101         // should ignore it, stay in L2ConnectingState
1102         assertEquals("L2ConnectingState", getCurrentState().getName());
1103 
1104         // send expected new network SSID
1105         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1106                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(config.SSID)));
1107         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1108                 new NetworkConnectionEventInfo(
1109                         OTHER_NETWORK_ID, wifiSsid, TEST_BSSID_STR1, false));
1110         mLooper.dispatchAll();
1111 
1112         // then move to next state
1113         assertEquals("L3ProvisioningState", getCurrentState().getName());
1114     }
1115 
1116     /**
1117      * When the SIM card was removed, if the current wifi connection is not using it, the connection
1118      * should be kept.
1119      */
1120     @Test
testResetSimWhenNonConnectedSimRemoved()1121     public void testResetSimWhenNonConnectedSimRemoved() throws Exception {
1122         setupEapSimConnection();
1123         doReturn(true).when(mWifiCarrierInfoManager).isSimReady(eq(DATA_SUBID));
1124         mCmi.sendMessage(ClientModeImpl.CMD_RESET_SIM_NETWORKS,
1125                 ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED);
1126         mLooper.dispatchAll();
1127 
1128         verify(mSimRequiredNotifier, never()).showSimRequiredNotification(any(), any());
1129         assertEquals("L3ProvisioningState", getCurrentState().getName());
1130     }
1131 
1132     /**
1133      * When the SIM card was removed, if the current wifi connection is using it, the connection
1134      * should be disconnected, otherwise, the connection shouldn't be impacted.
1135      */
1136     @Test
testResetSimWhenConnectedSimRemoved()1137     public void testResetSimWhenConnectedSimRemoved() throws Exception {
1138         setupEapSimConnection();
1139         doReturn(false).when(mWifiCarrierInfoManager).isSimReady(eq(DATA_SUBID));
1140         mCmi.sendMessage(ClientModeImpl.CMD_RESET_SIM_NETWORKS,
1141                 ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED);
1142         mLooper.dispatchAll();
1143 
1144         verify(mSimRequiredNotifier).showSimRequiredNotification(any(), any());
1145         verify(mWifiNative, times(2)).removeAllNetworks(WIFI_IFACE_NAME);
1146     }
1147 
1148     /**
1149      * When the SIM card was removed, if the current wifi connection is using it, the connection
1150      * should be disconnected, otherwise, the connection shouldn't be impacted.
1151      */
1152     @Test
testResetSimWhenConnectedSimRemovedAfterNetworkRemoval()1153     public void testResetSimWhenConnectedSimRemovedAfterNetworkRemoval() throws Exception {
1154         setupEapSimConnection();
1155         doReturn(false).when(mWifiCarrierInfoManager).isSimReady(eq(DATA_SUBID));
1156         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null);
1157         mCmi.sendMessage(ClientModeImpl.CMD_RESET_SIM_NETWORKS,
1158                 ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED);
1159         mLooper.dispatchAll();
1160 
1161         verify(mSimRequiredNotifier, never()).showSimRequiredNotification(any(), any());
1162         assertEquals("L3ProvisioningState", getCurrentState().getName());
1163     }
1164 
1165     /**
1166      * When the default data SIM is changed, if the current wifi connection is carrier wifi,
1167      * the connection should be disconnected.
1168      */
1169     @Test
testResetSimWhenDefaultDataSimChanged()1170     public void testResetSimWhenDefaultDataSimChanged() throws Exception {
1171         setupEapSimConnection();
1172         mCmi.sendMessage(ClientModeImpl.CMD_RESET_SIM_NETWORKS,
1173                 ClientModeImpl.RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED);
1174         mLooper.dispatchAll();
1175 
1176         verify(mWifiNative, times(2)).removeAllNetworks(WIFI_IFACE_NAME);
1177         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
1178                 eq(StaEvent.DISCONNECT_RESET_SIM_NETWORKS));
1179     }
1180 
1181     /**
1182      * Tests anonymous identity is set again whenever a connection is established for the carrier
1183      * that supports encrypted IMSI and anonymous identity and no real pseudonym was provided.
1184      */
1185     @Test
testSetAnonymousIdentityWhenConnectionIsEstablishedNoPseudonym()1186     public void testSetAnonymousIdentityWhenConnectionIsEstablishedNoPseudonym() throws Exception {
1187         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1188                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1189         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1190         String expectedAnonymousIdentity = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
1191 
1192         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1193                 .thenReturn(DATA_SUBID);
1194         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1195         when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(anyInt())).thenReturn(true);
1196         when(mWifiCarrierInfoManager.getAnonymousIdentityWith3GppRealm(any()))
1197                 .thenReturn(expectedAnonymousIdentity);
1198 
1199         // Initial value should be "not set"
1200         assertEquals("", mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1201 
1202         triggerConnect();
1203 
1204         // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
1205         assertEquals(expectedAnonymousIdentity,
1206                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1207 
1208         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1209                 .thenReturn(mScanDetailCache);
1210         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1211                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1212         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1213                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1214         when(mWifiNative.getEapAnonymousIdentity(anyString()))
1215                 .thenReturn(expectedAnonymousIdentity);
1216 
1217         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1218                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1219         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1220                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1221         mLooper.dispatchAll();
1222 
1223         verify(mWifiNative).getEapAnonymousIdentity(any());
1224 
1225         // Post connection value should remain "not set"
1226         assertEquals("", mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1227         // verify that WifiConfigManager#addOrUpdateNetwork() was called to clear any previously
1228         // stored pseudonym. i.e. to enable Encrypted IMSI for subsequent connections.
1229         // Note: This test will fail if future logic will have additional conditions that would
1230         // trigger "add or update network" operation. The test needs to be updated to account for
1231         // this change.
1232         verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
1233     }
1234 
1235     /**
1236      * Tests anonymous identity is set again whenever a connection is established for the carrier
1237      * that supports encrypted IMSI and anonymous identity but real pseudonym was provided for
1238      * subsequent connections.
1239      */
1240     @Test
testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonym()1241     public void testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonym()
1242             throws Exception {
1243         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1244                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1245         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1246         String expectedAnonymousIdentity = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
1247         String pseudonym = "83bcca9384fca@wlan.mnc456.mcc123.3gppnetwork.org";
1248 
1249         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1250                 .thenReturn(DATA_SUBID);
1251         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1252         when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(anyInt())).thenReturn(true);
1253         when(mWifiCarrierInfoManager.getAnonymousIdentityWith3GppRealm(any()))
1254                 .thenReturn(expectedAnonymousIdentity);
1255 
1256         triggerConnect();
1257 
1258         // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
1259         assertEquals(expectedAnonymousIdentity,
1260                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1261 
1262         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1263                 .thenReturn(mScanDetailCache);
1264         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1265                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1266         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1267                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1268         when(mWifiNative.getEapAnonymousIdentity(anyString()))
1269                 .thenReturn(pseudonym);
1270 
1271         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1272                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1273         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1274                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1275         mLooper.dispatchAll();
1276 
1277         verify(mWifiNative).getEapAnonymousIdentity(any());
1278         assertEquals(pseudonym,
1279                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1280         // Verify that WifiConfigManager#addOrUpdateNetwork() was called if there we received a
1281         // real pseudonym to be stored. i.e. Encrypted IMSI will be used once, followed by
1282         // pseudonym usage in all subsequent connections.
1283         // Note: This test will fail if future logic will have additional conditions that would
1284         // trigger "add or update network" operation. The test needs to be updated to account for
1285         // this change.
1286         verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
1287     }
1288 
1289     /**
1290      * Tests anonymous identity is set again whenever a connection is established for the carrier
1291      * that supports encrypted IMSI and anonymous identity but real but not decorated pseudonym was
1292      * provided for subsequent connections.
1293      */
1294     @Test
testSetAnonymousIdentityWhenConnectionIsEstablishedWithNonDecoratedPseudonym()1295     public void testSetAnonymousIdentityWhenConnectionIsEstablishedWithNonDecoratedPseudonym()
1296             throws Exception {
1297         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1298                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1299         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1300         String pseudonym = "83bcca9384fca";
1301         String realm = "wlan.mnc456.mcc123.3gppnetwork.org";
1302         String expectedAnonymousIdentity = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
1303 
1304         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1305                 .thenReturn(DATA_SUBID);
1306         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1307         when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(anyInt())).thenReturn(true);
1308         when(mWifiCarrierInfoManager.getAnonymousIdentityWith3GppRealm(any()))
1309                 .thenReturn(expectedAnonymousIdentity);
1310         doAnswer(invocation -> { return invocation.getArgument(1) + "@" + realm; })
1311                 .when(mWifiCarrierInfoManager).decoratePseudonymWith3GppRealm(any(), anyString());
1312         triggerConnect();
1313 
1314         // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
1315         assertEquals(expectedAnonymousIdentity,
1316                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1317 
1318         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1319                 .thenReturn(mScanDetailCache);
1320         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1321                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1322         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1323                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1324         when(mWifiNative.getEapAnonymousIdentity(anyString()))
1325                 .thenReturn(pseudonym);
1326 
1327         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1328                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1329         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1330                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1331         mLooper.dispatchAll();
1332 
1333         verify(mWifiNative).getEapAnonymousIdentity(any());
1334         assertEquals(pseudonym + "@" + realm,
1335                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1336         // Verify that WifiConfigManager#addOrUpdateNetwork() was called if there we received a
1337         // real pseudonym to be stored. i.e. Encrypted IMSI will be used once, followed by
1338         // pseudonym usage in all subsequent connections.
1339         // Note: This test will fail if future logic will have additional conditions that would
1340         // trigger "add or update network" operation. The test needs to be updated to account for
1341         // this change.
1342         verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
1343     }
1344 
1345     /**
1346      * Tests anonymous identity will be set to suggestion network.
1347      */
1348     @Test
testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonymForSuggestion()1349     public void testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonymForSuggestion()
1350             throws Exception {
1351         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1352                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1353         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1354         mConnectedNetwork.fromWifiNetworkSuggestion = true;
1355         String expectedAnonymousIdentity = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
1356         String pseudonym = "83bcca9384fca@wlan.mnc456.mcc123.3gppnetwork.org";
1357 
1358         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1359                 .thenReturn(DATA_SUBID);
1360         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1361         when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(anyInt())).thenReturn(true);
1362         when(mWifiCarrierInfoManager.getAnonymousIdentityWith3GppRealm(any()))
1363                 .thenReturn(expectedAnonymousIdentity);
1364 
1365         triggerConnect();
1366 
1367         // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
1368         assertEquals(expectedAnonymousIdentity,
1369                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1370 
1371         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1372                 .thenReturn(mScanDetailCache);
1373         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1374                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1375         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1376                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1377         when(mWifiNative.getEapAnonymousIdentity(anyString()))
1378                 .thenReturn(pseudonym);
1379 
1380         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1381                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1382         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1383                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1384         mLooper.dispatchAll();
1385 
1386         verify(mWifiNative).getEapAnonymousIdentity(any());
1387         assertEquals(pseudonym,
1388                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1389         // Verify that WifiConfigManager#addOrUpdateNetwork() was called if there we received a
1390         // real pseudonym to be stored. i.e. Encrypted IMSI will be used once, followed by
1391         // pseudonym usage in all subsequent connections.
1392         // Note: This test will fail if future logic will have additional conditions that would
1393         // trigger "add or update network" operation. The test needs to be updated to account for
1394         // this change.
1395         verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
1396         verify(mWifiNetworkSuggestionsManager).setAnonymousIdentity(any());
1397     }
1398 
1399     /**
1400      * Tests anonymous identity will be set to passpoint network.
1401      */
1402     @Test
testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonymForPasspoint()1403     public void testSetAnonymousIdentityWhenConnectionIsEstablishedWithPseudonymForPasspoint()
1404             throws Exception {
1405         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
1406                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
1407         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
1408         mConnectedNetwork.FQDN = WifiConfigurationTestUtil.TEST_FQDN;
1409         mConnectedNetwork.providerFriendlyName =
1410                 WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME;
1411         mConnectedNetwork.setPasspointUniqueId(WifiConfigurationTestUtil.TEST_FQDN + "_"
1412                 + WifiConfigurationTestUtil.TEST_FQDN.hashCode());
1413         String expectedAnonymousIdentity = "anonymous@wlan.mnc456.mcc123.3gppnetwork.org";
1414         String pseudonym = "83bcca9384fca@wlan.mnc456.mcc123.3gppnetwork.org";
1415 
1416         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
1417                 .thenReturn(DATA_SUBID);
1418         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
1419         when(mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(anyInt())).thenReturn(true);
1420         when(mWifiCarrierInfoManager.getAnonymousIdentityWith3GppRealm(any()))
1421                 .thenReturn(expectedAnonymousIdentity);
1422 
1423         triggerConnect();
1424 
1425         // CMD_START_CONNECT should have set anonymousIdentity to anonymous@<realm>
1426         assertEquals(expectedAnonymousIdentity,
1427                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1428 
1429         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
1430                 .thenReturn(mScanDetailCache);
1431         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
1432                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
1433         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
1434                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
1435         when(mWifiNative.getEapAnonymousIdentity(anyString()))
1436                 .thenReturn(pseudonym);
1437 
1438         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
1439                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
1440         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1441                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
1442         mLooper.dispatchAll();
1443 
1444         verify(mWifiNative).getEapAnonymousIdentity(any());
1445         assertEquals(pseudonym,
1446                 mConnectedNetwork.enterpriseConfig.getAnonymousIdentity());
1447         // Verify that WifiConfigManager#addOrUpdateNetwork() was called if there we received a
1448         // real pseudonym to be stored. i.e. Encrypted IMSI will be used once, followed by
1449         // pseudonym usage in all subsequent connections.
1450         // Note: This test will fail if future logic will have additional conditions that would
1451         // trigger "add or update network" operation. The test needs to be updated to account for
1452         // this change.
1453         verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt());
1454         verify(mPasspointManager).setAnonymousIdentity(any());
1455     }
1456     /**
1457      * Tests the Passpoint information is set in WifiInfo for Passpoint AP connection.
1458      */
1459     @Test
connectPasspointAp()1460     public void connectPasspointAp() throws Exception {
1461         WifiConfiguration config = spy(WifiConfigurationTestUtil.createPasspointNetwork());
1462         config.SSID = TEST_WIFI_SSID.toString();
1463         config.BSSID = TEST_BSSID_STR;
1464         config.networkId = FRAMEWORK_NETWORK_ID;
1465         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1466         setupAndStartConnectSequence(config);
1467         validateSuccessfulConnectSequence(config);
1468 
1469         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1470                 new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1471                         SupplicantState.ASSOCIATING));
1472         mLooper.dispatchAll();
1473 
1474         WifiInfo wifiInfo = mWifiInfo;
1475         assertNotNull(wifiInfo);
1476         assertEquals(WifiConfigurationTestUtil.TEST_FQDN, wifiInfo.getPasspointFqdn());
1477         assertEquals(WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME,
1478                 wifiInfo.getPasspointProviderFriendlyName());
1479     }
1480 
1481     /**
1482      * Tests that Passpoint fields in WifiInfo are reset when connecting to a non-Passpoint network
1483      * during DisconnectedState.
1484      * @throws Exception
1485      */
1486     @Test
testResetWifiInfoPasspointFields()1487     public void testResetWifiInfoPasspointFields() throws Exception {
1488         WifiConfiguration config = spy(WifiConfigurationTestUtil.createPasspointNetwork());
1489         config.SSID = TEST_WIFI_SSID.toString();
1490         config.BSSID = TEST_BSSID_STR;
1491         config.networkId = PASSPOINT_NETWORK_ID;
1492         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1493         setupAndStartConnectSequence(config);
1494         validateSuccessfulConnectSequence(config);
1495 
1496         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1497                 new StateChangeResult(PASSPOINT_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1498                         SupplicantState.ASSOCIATING));
1499         mLooper.dispatchAll();
1500 
1501         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1502                 new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1503                         SupplicantState.ASSOCIATING));
1504         mLooper.dispatchAll();
1505 
1506         WifiInfo wifiInfo = mWifiInfo;
1507         assertNotNull(wifiInfo);
1508         assertNull(wifiInfo.getPasspointFqdn());
1509         assertNull(wifiInfo.getPasspointProviderFriendlyName());
1510     }
1511 
1512     /**
1513      * Tests the OSU information is set in WifiInfo for OSU AP connection.
1514      */
1515     @Test
connectOsuAp()1516     public void connectOsuAp() throws Exception {
1517         WifiConfiguration osuConfig = spy(WifiConfigurationTestUtil.createEphemeralNetwork());
1518         osuConfig.SSID = TEST_WIFI_SSID.toString();
1519         osuConfig.BSSID = TEST_BSSID_STR;
1520         osuConfig.osu = true;
1521         osuConfig.networkId = FRAMEWORK_NETWORK_ID;
1522         osuConfig.providerFriendlyName = WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME;
1523         osuConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1524         setupAndStartConnectSequence(osuConfig);
1525         validateSuccessfulConnectSequence(osuConfig);
1526 
1527         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1528                 new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1529                         SupplicantState.ASSOCIATING));
1530         mLooper.dispatchAll();
1531 
1532         WifiInfo wifiInfo = mWifiInfo;
1533         assertNotNull(wifiInfo);
1534         assertTrue(wifiInfo.isOsuAp());
1535         assertEquals(WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME,
1536                 wifiInfo.getPasspointProviderFriendlyName());
1537     }
1538 
1539     /**
1540      * Tests that OSU fields in WifiInfo are reset when connecting to a non-OSU network during
1541      * DisconnectedState.
1542      * @throws Exception
1543      */
1544     @Test
testResetWifiInfoOsuFields()1545     public void testResetWifiInfoOsuFields() throws Exception {
1546         WifiConfiguration osuConfig = spy(WifiConfigurationTestUtil.createEphemeralNetwork());
1547         osuConfig.SSID = TEST_WIFI_SSID.toString();
1548         osuConfig.BSSID = TEST_BSSID_STR;
1549         osuConfig.osu = true;
1550         osuConfig.networkId = PASSPOINT_NETWORK_ID;
1551         osuConfig.providerFriendlyName = WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME;
1552         osuConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1553         setupAndStartConnectSequence(osuConfig);
1554         validateSuccessfulConnectSequence(osuConfig);
1555 
1556         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1557                 new StateChangeResult(PASSPOINT_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1558                         SupplicantState.ASSOCIATING));
1559         mLooper.dispatchAll();
1560 
1561         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1562                 new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
1563                         SupplicantState.ASSOCIATING));
1564         mLooper.dispatchAll();
1565 
1566         WifiInfo wifiInfo = mWifiInfo;
1567         assertNotNull(wifiInfo);
1568         assertFalse(wifiInfo.isOsuAp());
1569     }
1570 
1571     /**
1572      * Verify that WifiStateTracker is called if wifi is disabled while connected.
1573      */
1574     @Test
verifyWifiStateTrackerUpdatedWhenDisabled()1575     public void verifyWifiStateTrackerUpdatedWhenDisabled() throws Exception {
1576         connect();
1577 
1578         mCmi.stop();
1579         mLooper.dispatchAll();
1580         verify(mWifiStateTracker).updateState(WIFI_IFACE_NAME, WifiStateTracker.DISCONNECTED);
1581     }
1582 
1583     /**
1584      * Tests the network connection initiation sequence with no network request pending from
1585      * from WifiNetworkFactory when we're already connected to a different network.
1586      * This simulates the connect sequence using the public
1587      * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we invoke
1588      * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
1589      */
1590     @Test
triggerConnectWithNoNetworkRequestAndAlreadyConnected()1591     public void triggerConnectWithNoNetworkRequestAndAlreadyConnected() throws Exception {
1592         // Simulate the first connection.
1593         connect();
1594 
1595         // Remove the network requests.
1596         when(mWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1597         when(mUntrustedWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1598         when(mOemWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1599 
1600         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
1601         config.networkId = FRAMEWORK_NETWORK_ID + 1;
1602         setupAndStartConnectSequence(config);
1603         validateSuccessfulConnectSequence(config);
1604         verify(mWifiPermissionsUtil, atLeastOnce()).checkNetworkSettingsPermission(anyInt());
1605     }
1606 
1607     /**
1608      * Tests the network connection initiation sequence from a non-privileged app with no network
1609      * request pending from from WifiNetworkFactory when we're already connected to a different
1610      * network.
1611      * This simulates the connect sequence using the public
1612      * {@link WifiManager#enableNetwork(int, boolean)} and ensures that we don't invoke
1613      * {@link WifiNative#connectToNetwork(WifiConfiguration)}.
1614      */
1615     @Test
triggerConnectWithNoNetworkRequestAndAlreadyConnectedButNonPrivilegedApp()1616     public void triggerConnectWithNoNetworkRequestAndAlreadyConnectedButNonPrivilegedApp()
1617             throws Exception {
1618         // Simulate the first connection.
1619         connect();
1620 
1621         // Remove the network requests.
1622         when(mWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1623         when(mUntrustedWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1624         when(mOemWifiNetworkFactory.hasConnectionRequests()).thenReturn(false);
1625 
1626         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
1627 
1628         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
1629         config.networkId = FRAMEWORK_NETWORK_ID + 1;
1630         setupAndStartConnectSequence(config);
1631         verify(mWifiConnectivityManager).prepareForForcedConnection(eq(config.networkId));
1632         verify(mWifiConfigManager, never())
1633                 .getConfiguredNetworkWithoutMasking(eq(config.networkId));
1634         verify(mWifiNative, never()).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
1635         verify(mWifiPermissionsUtil, times(2)).checkNetworkSettingsPermission(anyInt());
1636     }
1637 
1638     /**
1639      * If caller tries to connect to a network that is already connected, the connection request
1640      * should succeed.
1641      *
1642      * Test: Create and connect to a network, then try to reconnect to the same network. Verify
1643      * that connection request returns with CONNECT_NETWORK_SUCCEEDED.
1644      */
1645     @Test
reconnectToConnectedNetworkWithNetworkId()1646     public void reconnectToConnectedNetworkWithNetworkId() throws Exception {
1647         connect();
1648 
1649         // try to reconnect
1650         IActionListener connectActionListener = mock(IActionListener.class);
1651         mCmi.connectNetwork(
1652                 new NetworkUpdateResult(FRAMEWORK_NETWORK_ID),
1653                 new ActionListenerWrapper(connectActionListener),
1654                 Binder.getCallingUid());
1655         mLooper.dispatchAll();
1656         verify(connectActionListener).onSuccess();
1657 
1658         // Verify that we didn't trigger a second connection.
1659         verify(mWifiNative, times(1)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1660     }
1661 
1662     /**
1663      * If caller tries to connect to a network that is already connected, the connection request
1664      * should succeed.
1665      *
1666      * Test: Create and connect to a network, then try to reconnect to the same network. Verify
1667      * that connection request returns with CONNECT_NETWORK_SUCCEEDED.
1668      */
1669     @Test
reconnectToConnectedNetworkWithConfig()1670     public void reconnectToConnectedNetworkWithConfig() throws Exception {
1671         connect();
1672 
1673         // try to reconnect
1674         IActionListener connectActionListener = mock(IActionListener.class);
1675         int callingUid = Binder.getCallingUid();
1676         mCmi.connectNetwork(
1677                 new NetworkUpdateResult(FRAMEWORK_NETWORK_ID),
1678                 new ActionListenerWrapper(connectActionListener),
1679                 callingUid);
1680         mLooper.dispatchAll();
1681         verify(connectActionListener).onSuccess();
1682 
1683         // Verify that we didn't trigger a second connection.
1684         verify(mWifiNative, times(1)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1685     }
1686 
1687     /**
1688      * If caller tries to connect to a network that is already connecting, the connection request
1689      * should succeed.
1690      *
1691      * Test: Create and trigger connect to a network, then try to reconnect to the same network.
1692      * Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED and did not trigger a
1693      * new connection.
1694      */
1695     @Test
reconnectToConnectingNetwork()1696     public void reconnectToConnectingNetwork() throws Exception {
1697         triggerConnect();
1698 
1699         // try to reconnect to the same network (before connection is established).
1700         IActionListener connectActionListener = mock(IActionListener.class);
1701         mCmi.connectNetwork(
1702                 new NetworkUpdateResult(FRAMEWORK_NETWORK_ID),
1703                 new ActionListenerWrapper(connectActionListener),
1704                 Binder.getCallingUid());
1705         mLooper.dispatchAll();
1706         verify(connectActionListener).onSuccess();
1707 
1708         // Verify that we didn't trigger a second connection.
1709         verify(mWifiNative, times(1)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1710     }
1711 
1712     /**
1713      * If caller tries to connect to a network that is already connecting, the connection request
1714      * should succeed.
1715      *
1716      * Test: Create and trigger connect to a network, then try to reconnect to the same network.
1717      * Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED and did trigger a new
1718      * connection.
1719      */
1720     @Test
reconnectToConnectingNetworkWithCredentialChange()1721     public void reconnectToConnectingNetworkWithCredentialChange() throws Exception {
1722         triggerConnect();
1723 
1724         // try to reconnect to the same network with a credential changed (before connection is
1725         // established).
1726         NetworkUpdateResult networkUpdateResult = new NetworkUpdateResult(
1727                 FRAMEWORK_NETWORK_ID,
1728                 false /* ip */,
1729                 false /* proxy */,
1730                 true /* credential */,
1731                 false /* isNewNetwork */);
1732         IActionListener connectActionListener = mock(IActionListener.class);
1733         mCmi.connectNetwork(
1734                 networkUpdateResult,
1735                 new ActionListenerWrapper(connectActionListener),
1736                 Binder.getCallingUid());
1737         mLooper.dispatchAll();
1738         verify(connectActionListener).onSuccess();
1739 
1740         // Verify that we triggered a second connection.
1741         verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1742     }
1743 
1744     /**
1745      * If caller tries to connect to a network that previously failed connection, the connection
1746      * request should succeed.
1747      *
1748      * Test: Create and trigger connect to a network, then fail the connection. Now try to reconnect
1749      * to the same network. Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED
1750      * and did trigger a new * connection.
1751      */
1752     @Test
connectAfterAssociationRejection()1753     public void connectAfterAssociationRejection() throws Exception {
1754         triggerConnect();
1755 
1756         // fail the connection.
1757         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
1758                 new AssocRejectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR,
1759                         ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, false));
1760         mLooper.dispatchAll();
1761 
1762         IActionListener connectActionListener = mock(IActionListener.class);
1763         mCmi.connectNetwork(
1764                 new NetworkUpdateResult(FRAMEWORK_NETWORK_ID),
1765                 new ActionListenerWrapper(connectActionListener),
1766                 Binder.getCallingUid());
1767         mLooper.dispatchAll();
1768         verify(connectActionListener).onSuccess();
1769 
1770         // Verify that we triggered a second connection.
1771         verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1772     }
1773 
1774     /**
1775      * If caller tries to connect to a network that previously failed connection, the connection
1776      * request should succeed.
1777      *
1778      * Test: Create and trigger connect to a network, then fail the connection. Now try to reconnect
1779      * to the same network. Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED
1780      * and did trigger a new * connection.
1781      */
1782     @Test
connectAfterConnectionFailure()1783     public void connectAfterConnectionFailure() throws Exception {
1784         triggerConnect();
1785 
1786         // fail the connection.
1787         DisconnectEventInfo disconnectEventInfo =
1788                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
1789         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
1790         mLooper.dispatchAll();
1791 
1792         IActionListener connectActionListener = mock(IActionListener.class);
1793         mCmi.connectNetwork(
1794                 new NetworkUpdateResult(FRAMEWORK_NETWORK_ID),
1795                 new ActionListenerWrapper(connectActionListener),
1796                 Binder.getCallingUid());
1797         mLooper.dispatchAll();
1798         verify(connectActionListener).onSuccess();
1799 
1800         // Verify that we triggered a second connection.
1801         verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
1802     }
1803 
1804     /**
1805      * If caller tries to connect to a new network while still provisioning the current one,
1806      * the connection attempt should succeed.
1807      */
1808     @Test
connectWhileObtainingIp()1809     public void connectWhileObtainingIp() throws Exception {
1810         initializeAndAddNetworkAndVerifySuccess();
1811 
1812         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
1813 
1814         startConnectSuccess();
1815 
1816         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1817                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
1818         mLooper.dispatchAll();
1819 
1820         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1821                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
1822                         SupplicantState.COMPLETED));
1823         mLooper.dispatchAll();
1824 
1825         assertEquals("L3ProvisioningState", getCurrentState().getName());
1826 
1827         // Connect to a different network
1828         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
1829         config.networkId = FRAMEWORK_NETWORK_ID + 1;
1830         setupAndStartConnectSequence(config);
1831         validateSuccessfulConnectSequence(config);
1832 
1833         // Disconnection from previous network.
1834         DisconnectEventInfo disconnectEventInfo =
1835                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
1836         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
1837         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1838                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
1839                         SupplicantState.DISCONNECTED));
1840         mLooper.dispatchAll();
1841 
1842         // Ensure we don't end the new connection event.
1843         verify(mWifiMetrics, never()).endConnectionEvent(
1844                 any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION),
1845                 anyInt(), anyInt(), anyInt());
1846         verify(mWifiConnectivityManager).prepareForForcedConnection(FRAMEWORK_NETWORK_ID + 1);
1847     }
1848 
1849     /**
1850      * If there is a network removal while still connecting to it, the connection
1851      * should be aborted.
1852      */
1853     @Test
networkRemovalWhileObtainingIp()1854     public void networkRemovalWhileObtainingIp() throws Exception {
1855         initializeAndAddNetworkAndVerifySuccess();
1856 
1857         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
1858 
1859         startConnectSuccess();
1860 
1861         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1862                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
1863         mLooper.dispatchAll();
1864 
1865         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1866                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
1867                         SupplicantState.COMPLETED));
1868         mLooper.dispatchAll();
1869 
1870         assertEquals("L3ProvisioningState", getCurrentState().getName());
1871         reset(mWifiNative);
1872 
1873         // Simulate the target network removal & the disconnect trigger.
1874         WifiConfiguration removedNetwork = new WifiConfiguration();
1875         removedNetwork.networkId = FRAMEWORK_NETWORK_ID;
1876         mConfigUpdateListenerCaptor.getValue().onNetworkRemoved(removedNetwork);
1877         mLooper.dispatchAll();
1878 
1879         verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
1880         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
1881         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
1882                 eq(StaEvent.DISCONNECT_NETWORK_REMOVED));
1883 
1884         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID)).thenReturn(null);
1885         DisconnectEventInfo disconnectEventInfo =
1886                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
1887         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
1888         mLooper.dispatchAll();
1889 
1890         assertEquals("DisconnectedState", getCurrentState().getName());
1891     }
1892 
1893     /**
1894      * Tests that manual connection to a network (from settings app) logs the correct nominator ID.
1895      */
1896     @Test
testManualConnectNominator()1897     public void testManualConnectNominator() throws Exception {
1898         initializeAndAddNetworkAndVerifySuccess();
1899 
1900         WifiConfiguration config = new WifiConfiguration();
1901         config.networkId = TEST_NETWORK_ID;
1902         when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(config);
1903 
1904         IActionListener connectActionListener = mock(IActionListener.class);
1905         mCmi.connectNetwork(
1906                 new NetworkUpdateResult(TEST_NETWORK_ID),
1907                 new ActionListenerWrapper(connectActionListener),
1908                 Process.SYSTEM_UID);
1909         mLooper.dispatchAll();
1910         verify(connectActionListener).onSuccess();
1911 
1912         verify(mWifiMetrics).setNominatorForNetwork(TEST_NETWORK_ID,
1913                 WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL);
1914     }
1915 
startConnectSuccess()1916     private void startConnectSuccess() throws Exception {
1917         startConnectSuccess(FRAMEWORK_NETWORK_ID);
1918     }
1919 
startConnectSuccess(int networkId)1920     private void startConnectSuccess(int networkId) throws Exception {
1921         IActionListener connectActionListener = mock(IActionListener.class);
1922         mCmi.connectNetwork(
1923                 new NetworkUpdateResult(networkId),
1924                 new ActionListenerWrapper(connectActionListener),
1925                 Binder.getCallingUid());
1926         mLooper.dispatchAll();
1927         verify(connectActionListener).onSuccess();
1928     }
1929 
1930     @Test
testDhcpFailure()1931     public void testDhcpFailure() throws Exception {
1932         initializeAndAddNetworkAndVerifySuccess();
1933 
1934         startConnectSuccess();
1935 
1936         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1937                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
1938                         SupplicantState.ASSOCIATED));
1939         mLooper.dispatchAll();
1940 
1941         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
1942                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
1943         mLooper.dispatchAll();
1944         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
1945 
1946         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1947                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
1948                         SupplicantState.COMPLETED));
1949         mLooper.dispatchAll();
1950 
1951         assertEquals("L3ProvisioningState", getCurrentState().getName());
1952         injectDhcpFailure();
1953         mLooper.dispatchAll();
1954 
1955         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
1956         // Verify this is not counted as a IP renewal failure
1957         verify(mWifiMetrics, never()).incrementIpRenewalFailure();
1958         // Verifies that WifiLastResortWatchdog be notified
1959         // by DHCP failure
1960         verify(mWifiLastResortWatchdog, times(2)).noteConnectionFailureAndTriggerIfNeeded(
1961                 eq(TEST_SSID), eq(TEST_BSSID_STR),
1962                 eq(WifiLastResortWatchdog.FAILURE_CODE_DHCP), anyBoolean());
1963         verify(mWifiBlocklistMonitor, times(2)).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
1964                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_DHCP_FAILURE), anyInt());
1965         verify(mWifiBlocklistMonitor, times(2)).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
1966                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_DHCP_FAILURE), anyInt());
1967         verify(mWifiBlocklistMonitor, never()).handleDhcpProvisioningSuccess(
1968                 TEST_BSSID_STR, TEST_SSID);
1969         verify(mWifiBlocklistMonitor, never()).handleNetworkValidationSuccess(
1970                 TEST_BSSID_STR, TEST_SSID);
1971     }
1972 
1973     /**
1974      * Verify that a IP renewal failure is logged when IP provisioning fail in the
1975      * L3ConnectedState.
1976      */
1977     @Test
testDhcpRenewalMetrics()1978     public void testDhcpRenewalMetrics() throws Exception {
1979         connect();
1980         injectDhcpFailure();
1981         mLooper.dispatchAll();
1982 
1983         verify(mWifiMetrics).incrementIpRenewalFailure();
1984     }
1985 
1986     /**
1987      * Verify that the network selection status will be updated with DISABLED_AUTHENTICATION_FAILURE
1988      * when wrong password authentication failure is detected and the network had been
1989      * connected previously.
1990      */
1991     @Test
testWrongPasswordWithPreviouslyConnected()1992     public void testWrongPasswordWithPreviouslyConnected() throws Exception {
1993         initializeAndAddNetworkAndVerifySuccess();
1994 
1995         startConnectSuccess();
1996 
1997         WifiConfiguration config = createTestNetwork(false);
1998         config.getNetworkSelectionStatus().setHasEverConnected(true);
1999         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
2000 
2001         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
2002                 WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
2003         DisconnectEventInfo disconnectEventInfo =
2004                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
2005         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2006         mLooper.dispatchAll();
2007 
2008         verify(mWrongPasswordNotifier, never()).onWrongPasswordError(anyString());
2009         verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
2010                 eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE));
2011 
2012         assertEquals("DisconnectedState", getCurrentState().getName());
2013     }
2014 
2015     /**
2016      * It is observed sometimes the WifiMonitor.NETWORK_DISCONNECTION_EVENT is observed before the
2017      * actual connection failure messages while making a connection.
2018      * The test make sure that make sure that the connection event is ended properly in the above
2019      * case.
2020      */
2021     @Test
testDisconnectionEventInL2ConnectingStateEndsConnectionEvent()2022     public void testDisconnectionEventInL2ConnectingStateEndsConnectionEvent() throws Exception {
2023         initializeAndAddNetworkAndVerifySuccess();
2024 
2025         startConnectSuccess();
2026 
2027         WifiConfiguration config = createTestNetwork(false);
2028         config.getNetworkSelectionStatus().setHasEverConnected(true);
2029         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
2030 
2031         DisconnectEventInfo disconnectEventInfo =
2032                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
2033         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2034         mLooper.dispatchAll();
2035 
2036         verify(mWifiMetrics).endConnectionEvent(
2037                 any(), eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION),
2038                 anyInt(), anyInt(), anyInt());
2039         verify(mWifiConnectivityManager).handleConnectionAttemptEnded(
2040                 any(), anyInt(), any(), any());
2041         assertEquals(WifiInfo.SECURITY_TYPE_UNKNOWN, mWifiInfo.getCurrentSecurityType());
2042         assertEquals("DisconnectedState", getCurrentState().getName());
2043     }
2044 
2045     /**
2046      * Verify that the network selection status will be updated with DISABLED_BY_WRONG_PASSWORD
2047      * when wrong password authentication failure is detected and the network has never been
2048      * connected.
2049      */
2050     @Test
testWrongPasswordWithNeverConnected()2051     public void testWrongPasswordWithNeverConnected() throws Exception {
2052         initializeAndAddNetworkAndVerifySuccess();
2053 
2054         startConnectSuccess();
2055 
2056         WifiConfiguration config = new WifiConfiguration();
2057         config.SSID = TEST_SSID;
2058         config.getNetworkSelectionStatus().setHasEverConnected(false);
2059         config.carrierId = CARRIER_ID_1;
2060         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
2061 
2062         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
2063                 WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
2064         DisconnectEventInfo disconnectEventInfo =
2065                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
2066         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2067         mLooper.dispatchAll();
2068 
2069         verify(mWrongPasswordNotifier).onWrongPasswordError(eq(TEST_SSID));
2070         verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
2071                 eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD));
2072         verify(mWifiMetrics).incrementNumOfCarrierWifiConnectionAuthFailure();
2073         assertEquals("DisconnectedState", getCurrentState().getName());
2074     }
2075 
2076     /**
2077      * Verify that the function resetCarrierKeysForImsiEncryption() in TelephonyManager
2078      * is called when a Authentication failure is detected with a vendor specific EAP Error
2079      * of certification expired while using EAP-SIM
2080      * In this test case, it is assumed that the network had been connected previously.
2081      */
2082     @Test
testEapSimErrorVendorSpecific()2083     public void testEapSimErrorVendorSpecific() throws Exception {
2084         when(mWifiMetrics.startConnectionEvent(any(), any(), anyString(), anyInt()))
2085                 .thenReturn(80000);
2086         initializeAndAddNetworkAndVerifySuccess();
2087 
2088         startConnectSuccess();
2089 
2090         WifiConfiguration config = new WifiConfiguration();
2091         config.SSID = TEST_SSID;
2092         config.getNetworkSelectionStatus().setHasEverConnected(true);
2093         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
2094         config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
2095         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
2096         when(mWifiScoreCard.detectAbnormalConnectionFailure(anyString()))
2097                 .thenReturn(WifiHealthMonitor.REASON_AUTH_FAILURE);
2098 
2099         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
2100                 WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE,
2101                 WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED);
2102         mLooper.dispatchAll();
2103 
2104         verify(mEapFailureNotifier).onEapFailure(
2105                 WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED, config, true);
2106         verify(mWifiCarrierInfoManager).resetCarrierKeysForImsiEncryption(any());
2107         verify(mDeviceConfigFacade).isAbnormalConnectionFailureBugreportEnabled();
2108         verify(mWifiScoreCard).detectAbnormalConnectionFailure(anyString());
2109         verify(mWifiDiagnostics, times(2)).takeBugReport(anyString(), anyString());
2110     }
2111 
2112     /**
2113      * Verify that the function resetCarrierKeysForImsiEncryption() in TelephonyManager
2114      * is not called when a Authentication failure is detected with a vendor specific EAP Error
2115      * of certification expired while using other methods than EAP-SIM, EAP-AKA, or EAP-AKA'.
2116      */
2117     @Test
testEapTlsErrorVendorSpecific()2118     public void testEapTlsErrorVendorSpecific() throws Exception {
2119         initializeAndAddNetworkAndVerifySuccess();
2120 
2121         startConnectSuccess();
2122 
2123         WifiConfiguration config = new WifiConfiguration();
2124         config.getNetworkSelectionStatus().setHasEverConnected(true);
2125         config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
2126         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
2127         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
2128 
2129         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
2130                 WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE,
2131                 WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED);
2132         mLooper.dispatchAll();
2133 
2134         verify(mWifiCarrierInfoManager, never()).resetCarrierKeysForImsiEncryption(any());
2135     }
2136 
2137     /**
2138      * Verify that the network selection status will be updated with
2139      * DISABLED_AUTHENTICATION_NO_SUBSCRIBED when service is not subscribed.
2140      */
2141     @Test
testEapSimNoSubscribedError()2142     public void testEapSimNoSubscribedError() throws Exception {
2143         initializeAndAddNetworkAndVerifySuccess();
2144 
2145         startConnectSuccess();
2146 
2147         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null);
2148 
2149         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
2150                 WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE,
2151                 WifiNative.EAP_SIM_NOT_SUBSCRIBED);
2152         mLooper.dispatchAll();
2153 
2154         verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
2155                 eq(WifiConfiguration.NetworkSelectionStatus
2156                         .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION));
2157     }
2158 
2159     @Test
testBadNetworkEvent()2160     public void testBadNetworkEvent() throws Exception {
2161         initializeAndAddNetworkAndVerifySuccess();
2162 
2163         startConnectSuccess();
2164 
2165         DisconnectEventInfo disconnectEventInfo =
2166                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
2167         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2168         mLooper.dispatchAll();
2169 
2170         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2171                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
2172                         SupplicantState.COMPLETED));
2173         mLooper.dispatchAll();
2174 
2175         assertEquals("DisconnectedState", getCurrentState().getName());
2176         verify(mWifiDiagnostics, never()).takeBugReport(anyString(), anyString());
2177     }
2178 
2179 
2180     @Test
getWhatToString()2181     public void getWhatToString() throws Exception {
2182         assertEquals("CMD_PRE_DHCP_ACTION", mCmi.getWhatToString(CMD_PRE_DHCP_ACTION));
2183         assertEquals("CMD_IP_REACHABILITY_LOST", mCmi.getWhatToString(
2184                 ClientModeImpl.CMD_IP_REACHABILITY_LOST));
2185     }
2186 
2187     @Test
disconnect()2188     public void disconnect() throws Exception {
2189         when(mWifiScoreCard.detectAbnormalDisconnection(any()))
2190                 .thenReturn(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL);
2191         InOrder inOrderWifiLockManager = inOrder(mWifiLockManager);
2192         connect();
2193         inOrderWifiLockManager.verify(mWifiLockManager)
2194                 .updateWifiClientConnected(mClientModeManager, true);
2195 
2196         DisconnectEventInfo disconnectEventInfo =
2197                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
2198         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2199         mLooper.dispatchAll();
2200         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2201                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
2202                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
2203         mLooper.dispatchAll();
2204 
2205         verify(mWifiStateTracker).updateState(WIFI_IFACE_NAME, WifiStateTracker.DISCONNECTED);
2206         assertEquals("DisconnectedState", getCurrentState().getName());
2207         verify(mCmiMonitor).onConnectionEnd(mClientModeManager);
2208         inOrderWifiLockManager.verify(mWifiLockManager)
2209                 .updateWifiClientConnected(mClientModeManager, false);
2210         verify(mWifiScoreCard).detectAbnormalDisconnection(WIFI_IFACE_NAME);
2211         verify(mWifiDiagnostics).takeBugReport(anyString(), anyString());
2212         verify(mWifiNative).disableNetwork(WIFI_IFACE_NAME);
2213         // Set MAC address thrice - once at bootup, once for new connection, once for disconnect.
2214         verify(mWifiNative, times(3)).setStaMacAddress(eq(WIFI_IFACE_NAME), any());
2215         // ClientModeManager should only be stopped when in lingering mode
2216         verify(mClientModeManager, never()).stop();
2217     }
2218 
2219     @Test
secondaryRoleCmmDisconnected_stopsClientModeManager()2220     public void secondaryRoleCmmDisconnected_stopsClientModeManager() throws Exception {
2221         // Owning ClientModeManager has role SECONDARY_TRANSIENT
2222         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
2223 
2224         connect();
2225 
2226         // ClientModeManager never stopped
2227         verify(mClientModeManager, never()).stop();
2228 
2229         // Disconnected from network
2230         DisconnectEventInfo disconnectEventInfo =
2231                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
2232         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2233         mLooper.dispatchAll();
2234         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2235                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
2236                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
2237         mLooper.dispatchAll();
2238 
2239         assertEquals("DisconnectedState", getCurrentState().getName());
2240 
2241         // Since in lingering mode, disconnect => stop ClientModeManager
2242         verify(mClientModeManager).stop();
2243     }
2244 
2245     @Test
primaryCmmDisconnected_doesntStopsClientModeManager()2246     public void primaryCmmDisconnected_doesntStopsClientModeManager() throws Exception {
2247         // Owning ClientModeManager is primary
2248         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
2249 
2250         connect();
2251 
2252         // ClientModeManager never stopped
2253         verify(mClientModeManager, never()).stop();
2254 
2255         // Disconnected from network
2256         DisconnectEventInfo disconnectEventInfo =
2257                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
2258         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2259         mLooper.dispatchAll();
2260         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2261                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
2262                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
2263         mLooper.dispatchAll();
2264 
2265         assertEquals("DisconnectedState", getCurrentState().getName());
2266 
2267         // Since primary => don't stop ClientModeManager
2268         verify(mClientModeManager, never()).stop();
2269     }
2270 
2271     /**
2272      * Successfully connecting to a network will set WifiConfiguration's value of HasEverConnected
2273      * to true.
2274      *
2275      * Test: Successfully create and connect to a network. Check the config and verify
2276      * WifiConfiguration.getHasEverConnected() is true.
2277      */
2278     @Test
setHasEverConnectedTrueOnConnect()2279     public void setHasEverConnectedTrueOnConnect() throws Exception {
2280         connect();
2281         verify(mWifiConfigManager, atLeastOnce()).updateNetworkAfterConnect(eq(0), eq(false),
2282                 anyInt());
2283     }
2284 
2285     /**
2286      * Fail network connection attempt and verify HasEverConnected remains false.
2287      *
2288      * Test: Successfully create a network but fail when connecting. Check the config and verify
2289      * WifiConfiguration.getHasEverConnected() is false.
2290      */
2291     @Test
connectionFailureDoesNotSetHasEverConnectedTrue()2292     public void connectionFailureDoesNotSetHasEverConnectedTrue() throws Exception {
2293         testDhcpFailure();
2294         verify(mWifiConfigManager, never()).updateNetworkAfterConnect(eq(0), eq(false), anyInt());
2295     }
2296 
2297     @Test
iconQueryTest()2298     public void iconQueryTest() throws Exception {
2299         // TODO(b/31065385): Passpoint config management.
2300     }
2301 
2302     @Test
verboseLogRecSizeIsGreaterThanNormalSize()2303     public void verboseLogRecSizeIsGreaterThanNormalSize() {
2304         assertTrue(LOG_REC_LIMIT_IN_VERBOSE_MODE > mWifiGlobals.getClientModeImplNumLogRecs());
2305     }
2306 
2307     /**
2308      * Verifies that, by default, we allow only the "normal" number of log records.
2309      */
2310     @Test
normalLogRecSizeIsUsedByDefault()2311     public void normalLogRecSizeIsUsedByDefault() {
2312         mCmi.enableVerboseLogging(false);
2313         assertEquals(mWifiGlobals.getClientModeImplNumLogRecs(), mCmi.getLogRecMaxSize());
2314     }
2315 
2316     /**
2317      * Verifies that, in verbose mode, we allow a larger number of log records.
2318      */
2319     @Test
enablingVerboseLoggingUpdatesLogRecSize()2320     public void enablingVerboseLoggingUpdatesLogRecSize() {
2321         mCmi.enableVerboseLogging(true);
2322         assertEquals(LOG_REC_LIMIT_IN_VERBOSE_MODE, mCmi.getLogRecMaxSize());
2323     }
2324 
2325     @Test
disablingVerboseLoggingClearsRecords()2326     public void disablingVerboseLoggingClearsRecords() {
2327         mCmi.sendMessage(ClientModeImpl.CMD_DISCONNECT);
2328         mLooper.dispatchAll();
2329         assertTrue(mCmi.getLogRecSize() >= 1);
2330 
2331         mCmi.enableVerboseLogging(false);
2332         assertEquals(0, mCmi.getLogRecSize());
2333     }
2334 
2335     @Test
disablingVerboseLoggingUpdatesLogRecSize()2336     public void disablingVerboseLoggingUpdatesLogRecSize() {
2337         mCmi.enableVerboseLogging(true);
2338         mCmi.enableVerboseLogging(false);
2339         assertEquals(mWifiGlobals.getClientModeImplNumLogRecs(), mCmi.getLogRecMaxSize());
2340     }
2341 
2342     @Test
logRecsIncludeDisconnectCommand()2343     public void logRecsIncludeDisconnectCommand() {
2344         // There's nothing special about the DISCONNECT command. It's just representative of
2345         // "normal" commands.
2346         mCmi.sendMessage(ClientModeImpl.CMD_DISCONNECT);
2347         mLooper.dispatchAll();
2348         assertEquals(1, mCmi.copyLogRecs()
2349                 .stream()
2350                 .filter(logRec -> logRec.getWhat() == ClientModeImpl.CMD_DISCONNECT)
2351                 .count());
2352     }
2353 
2354     @Test
logRecsExcludeRssiPollCommandByDefault()2355     public void logRecsExcludeRssiPollCommandByDefault() {
2356         mCmi.enableVerboseLogging(false);
2357         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL);
2358         mLooper.dispatchAll();
2359         assertEquals(0, mCmi.copyLogRecs()
2360                 .stream()
2361                 .filter(logRec -> logRec.getWhat() == ClientModeImpl.CMD_RSSI_POLL)
2362                 .count());
2363     }
2364 
2365     @Test
logRecsIncludeRssiPollCommandWhenVerboseLoggingIsEnabled()2366     public void logRecsIncludeRssiPollCommandWhenVerboseLoggingIsEnabled() {
2367         mCmi.enableVerboseLogging(true);
2368         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL);
2369         mLooper.dispatchAll();
2370         assertEquals(1, mCmi.copyLogRecs()
2371                 .stream()
2372                 .filter(logRec -> logRec.getWhat() == ClientModeImpl.CMD_RSSI_POLL)
2373                 .count());
2374     }
2375 
2376     /**
2377      * Verify that syncStartSubscriptionProvisioning will redirect calls with right parameters
2378      * to {@link PasspointManager} with expected true being returned when in client mode.
2379      */
2380     @Test
syncStartSubscriptionProvisioningInClientMode()2381     public void syncStartSubscriptionProvisioningInClientMode() throws Exception {
2382         when(mPasspointManager.startSubscriptionProvisioning(anyInt(),
2383                 any(OsuProvider.class), any(IProvisioningCallback.class))).thenReturn(true);
2384         mLooper.startAutoDispatch();
2385         assertTrue(mCmi.syncStartSubscriptionProvisioning(
2386                 OTHER_USER_UID, mOsuProvider, mProvisioningCallback));
2387         verify(mPasspointManager).startSubscriptionProvisioning(OTHER_USER_UID, mOsuProvider,
2388                 mProvisioningCallback);
2389         mLooper.stopAutoDispatch();
2390     }
2391 
2392     @Test
testSyncGetCurrentNetwork()2393     public void testSyncGetCurrentNetwork() throws Exception {
2394         // syncGetCurrentNetwork() returns null when disconnected
2395         mLooper.startAutoDispatch();
2396         assertNull(mCmi.syncGetCurrentNetwork());
2397         mLooper.stopAutoDispatch();
2398 
2399         connect();
2400 
2401         // syncGetCurrentNetwork() returns non-null Network when connected
2402         mLooper.startAutoDispatch();
2403         assertEquals(mNetwork, mCmi.syncGetCurrentNetwork());
2404         mLooper.stopAutoDispatch();
2405     }
2406 
2407     /**
2408      *  Test that we disconnect from a network if it was removed while we are in the
2409      *  L3ProvisioningState.
2410      */
2411     @Test
disconnectFromNetworkWhenRemovedWhileObtainingIpAddr()2412     public void disconnectFromNetworkWhenRemovedWhileObtainingIpAddr() throws Exception {
2413         initializeAndAddNetworkAndVerifySuccess();
2414 
2415         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
2416 
2417         startConnectSuccess();
2418 
2419         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
2420                 .thenReturn(mScanDetailCache);
2421 
2422         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
2423                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
2424         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
2425                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
2426 
2427         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
2428                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
2429         mLooper.dispatchAll();
2430 
2431         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2432                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
2433                         SupplicantState.COMPLETED));
2434         mLooper.dispatchAll();
2435 
2436         assertEquals("L3ProvisioningState", getCurrentState().getName());
2437 
2438         // trigger removal callback to trigger disconnect.
2439         WifiConfiguration removedConfig = new WifiConfiguration();
2440         removedConfig.networkId = FRAMEWORK_NETWORK_ID;
2441         mConfigUpdateListenerCaptor.getValue().onNetworkRemoved(removedConfig);
2442 
2443         reset(mWifiConfigManager);
2444 
2445         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID)).thenReturn(null);
2446 
2447         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
2448         dhcpResults.baseConfiguration = new StaticIpConfiguration();
2449         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
2450         dhcpResults.baseConfiguration.ipAddress =
2451                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
2452         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
2453         dhcpResults.leaseDuration = 3600;
2454 
2455         injectDhcpSuccess(dhcpResults);
2456         mLooper.dispatchAll();
2457 
2458         verify(mWifiNative, times(2)).disconnect(WIFI_IFACE_NAME);
2459     }
2460 
2461     /**
2462      * Verifies that WifiInfo is updated upon SUPPLICANT_STATE_CHANGE_EVENT.
2463      */
2464     @Test
testWifiInfoUpdatedUponSupplicantStateChangedEvent()2465     public void testWifiInfoUpdatedUponSupplicantStateChangedEvent() throws Exception {
2466         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
2467         connect();
2468 
2469         // Set the scan detail cache for roaming target.
2470         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
2471                 .thenReturn(mScanDetailCache);
2472         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR1)).thenReturn(
2473                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1));
2474         when(mScanDetailCache.getScanResult(TEST_BSSID_STR1)).thenReturn(
2475                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1).getScanResult());
2476 
2477         // This simulates the behavior of roaming to network with |TEST_BSSID_STR1|, |sFreq1|.
2478         // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is updated.
2479         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2480                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR1,
2481                         SupplicantState.COMPLETED));
2482         mLooper.dispatchAll();
2483 
2484         WifiInfo wifiInfo = mWifiInfo;
2485         assertEquals(TEST_BSSID_STR1, wifiInfo.getBSSID());
2486         assertEquals(sFreq1, wifiInfo.getFrequency());
2487         assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
2488 
2489         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2490                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR1,
2491                         SupplicantState.DISCONNECTED));
2492         mLooper.dispatchAll();
2493 
2494         wifiInfo = mWifiInfo;
2495         assertNull(wifiInfo.getBSSID());
2496         assertEquals(WifiManager.UNKNOWN_SSID, wifiInfo.getSSID());
2497         assertEquals(WifiConfiguration.INVALID_NETWORK_ID, wifiInfo.getNetworkId());
2498         assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
2499         assertEquals("DisconnectedState", getCurrentState().getName());
2500     }
2501 
2502 
2503     /**
2504      * Verifies that WifiInfo is updated upon SUPPLICANT_STATE_CHANGE_EVENT.
2505      */
2506     @Test
testWifiInfoUpdatedUponSupplicantStateChangedEventWithWrongSsid()2507     public void testWifiInfoUpdatedUponSupplicantStateChangedEventWithWrongSsid() throws Exception {
2508         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
2509         connect();
2510 
2511         // Set the scan detail cache for roaming target.
2512         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
2513                 .thenReturn(mScanDetailCache);
2514         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR1)).thenReturn(
2515                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1));
2516         when(mScanDetailCache.getScanResult(TEST_BSSID_STR1)).thenReturn(
2517                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1).getScanResult());
2518 
2519         // This simulates the behavior of roaming to network with |TEST_BSSID_STR1|, |sFreq1|.
2520         // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is updated.
2521         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2522                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR1,
2523                         SupplicantState.COMPLETED));
2524         mLooper.dispatchAll();
2525 
2526         WifiInfo wifiInfo = mWifiInfo;
2527         assertEquals(TEST_BSSID_STR1, wifiInfo.getBSSID());
2528         assertEquals(sFreq1, wifiInfo.getFrequency());
2529         assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
2530 
2531         // Send state change event with wrong ssid.
2532         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2533                 new StateChangeResult(0, TEST_WIFI_SSID1, TEST_BSSID_STR,
2534                         SupplicantState.DISCONNECTED));
2535         mLooper.dispatchAll();
2536 
2537         wifiInfo = mWifiInfo;
2538         assertNull(wifiInfo.getBSSID());
2539         assertEquals(WifiManager.UNKNOWN_SSID, wifiInfo.getSSID());
2540         assertEquals(WifiConfiguration.INVALID_NETWORK_ID, wifiInfo.getNetworkId());
2541         assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
2542         assertEquals("DisconnectedState", getCurrentState().getName());
2543     }
2544 
2545     /**
2546      * Verifies that WifiInfo is updated upon CMD_ASSOCIATED_BSSID event.
2547      */
2548     @Test
testWifiInfoUpdatedUponAssociatedBSSIDEvent()2549     public void testWifiInfoUpdatedUponAssociatedBSSIDEvent() throws Exception {
2550         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
2551         connect();
2552 
2553         // Set the scan detail cache for roaming target.
2554         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
2555                 .thenReturn(mScanDetailCache);
2556         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR1)).thenReturn(
2557                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1));
2558         when(mScanDetailCache.getScanResult(TEST_BSSID_STR1)).thenReturn(
2559                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq1).getScanResult());
2560 
2561         // This simulates the behavior of roaming to network with |TEST_BSSID_STR1|, |sFreq1|.
2562         // Send a CMD_ASSOCIATED_BSSID, verify WifiInfo is updated.
2563         mCmi.sendMessage(WifiMonitor.ASSOCIATED_BSSID_EVENT, 0, 0, TEST_BSSID_STR1);
2564         mLooper.dispatchAll();
2565 
2566         WifiInfo wifiInfo = mWifiInfo;
2567         assertEquals(TEST_BSSID_STR1, wifiInfo.getBSSID());
2568         assertEquals(sFreq1, wifiInfo.getFrequency());
2569         assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
2570         verify(mContext, times(2)).sendStickyBroadcastAsUser(
2571                 argThat(new NetworkStateChangedIntentMatcher(CONNECTED)), any());
2572     }
2573 
2574     /**
2575      * Verifies that WifiInfo is cleared upon exiting and entering WifiInfo, and that it is not
2576      * updated by SUPPLICAN_STATE_CHANGE_EVENTs in ScanModeState.
2577      * This protects ClientModeImpl from  getting into a bad state where WifiInfo says wifi is
2578      * already Connected or Connecting, (when it is in-fact Disconnected), so
2579      * WifiConnectivityManager does not attempt any new Connections, freezing wifi.
2580      */
2581     @Test
testWifiInfoCleanedUpEnteringExitingConnectableState()2582     public void testWifiInfoCleanedUpEnteringExitingConnectableState() throws Exception {
2583         InOrder inOrderMetrics = inOrder(mWifiMetrics);
2584         Log.i(TAG, mCmi.getCurrentState().getName());
2585         String initialBSSID = "aa:bb:cc:dd:ee:ff";
2586         WifiInfo wifiInfo = mWifiInfo;
2587         wifiInfo.setBSSID(initialBSSID);
2588 
2589         // reset mWifiNative since initializeCmi() was called in setup()
2590         resetWifiNative();
2591 
2592         // Set CMI to CONNECT_MODE and verify state, and wifi enabled in ConnectivityManager
2593         initializeCmi();
2594         inOrderMetrics.verify(mWifiMetrics)
2595                 .setWifiState(WIFI_IFACE_NAME, WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
2596         inOrderMetrics.verify(mWifiMetrics)
2597                 .logStaEvent(WIFI_IFACE_NAME, StaEvent.TYPE_WIFI_ENABLED);
2598         assertNull(wifiInfo.getBSSID());
2599 
2600         // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is updated
2601         connect();
2602         assertEquals(TEST_BSSID_STR, wifiInfo.getBSSID());
2603         assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
2604 
2605         // Set CMI to DISABLED_MODE, verify state and wifi disabled in ConnectivityManager, and
2606         // WifiInfo is reset() and state set to DISCONNECTED
2607         mCmi.stop();
2608         mLooper.dispatchAll();
2609 
2610         inOrderMetrics.verify(mWifiMetrics).setWifiState(WIFI_IFACE_NAME,
2611                 WifiMetricsProto.WifiLog.WIFI_DISABLED);
2612         inOrderMetrics.verify(mWifiMetrics)
2613                 .logStaEvent(WIFI_IFACE_NAME, StaEvent.TYPE_WIFI_DISABLED);
2614         assertNull(wifiInfo.getBSSID());
2615         assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
2616     }
2617 
2618     @Test
testWifiInfoCleanedUpEnteringExitingConnectableState2()2619     public void testWifiInfoCleanedUpEnteringExitingConnectableState2() throws Exception {
2620         String initialBSSID = "aa:bb:cc:dd:ee:ff";
2621         InOrder inOrderMetrics = inOrder(mWifiMetrics);
2622 
2623         // Send a SUPPLICANT_STATE_CHANGE_EVENT, verify WifiInfo is not updated
2624         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
2625                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
2626                         SupplicantState.COMPLETED));
2627         mLooper.dispatchAll();
2628         assertNull(mWifiInfo.getBSSID());
2629         assertEquals(SupplicantState.DISCONNECTED, mWifiInfo.getSupplicantState());
2630     }
2631 
2632     @Test
testWifiInfoCleanedUpEnteringExitingConnectableState3()2633     public void testWifiInfoCleanedUpEnteringExitingConnectableState3() throws Exception {
2634         String initialBSSID = "aa:bb:cc:dd:ee:ff";
2635         InOrder inOrderMetrics = inOrder(mWifiMetrics);
2636 
2637         // Set the bssid to something, so we can verify it is cleared (just in case)
2638         mWifiInfo.setBSSID(initialBSSID);
2639 
2640         initializeCmi();
2641 
2642         inOrderMetrics.verify(mWifiMetrics)
2643                 .setWifiState(WIFI_IFACE_NAME, WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
2644         inOrderMetrics.verify(mWifiMetrics)
2645                 .logStaEvent(WIFI_IFACE_NAME, StaEvent.TYPE_WIFI_ENABLED);
2646         assertEquals("DisconnectedState", getCurrentState().getName());
2647         assertEquals(SupplicantState.DISCONNECTED, mWifiInfo.getSupplicantState());
2648         assertNull(mWifiInfo.getBSSID());
2649     }
2650 
2651     /**
2652      * Test that connected SSID and BSSID are exposed to system server.
2653      * Also tests that {@link ClientModeImpl#syncRequestConnectionInfo()} always
2654      * returns a copy of WifiInfo.
2655      */
2656     @Test
testConnectedIdsAreVisibleFromSystemServer()2657     public void testConnectedIdsAreVisibleFromSystemServer() throws Exception {
2658         WifiInfo wifiInfo = mWifiInfo;
2659         // Get into a connected state, with known BSSID and SSID
2660         connect();
2661         assertEquals(TEST_BSSID_STR, wifiInfo.getBSSID());
2662         assertEquals(TEST_WIFI_SSID, wifiInfo.getWifiSsid());
2663 
2664         mLooper.startAutoDispatch();
2665         WifiInfo connectionInfo = mCmi.syncRequestConnectionInfo();
2666         mLooper.stopAutoDispatch();
2667 
2668         assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
2669         assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
2670         assertEquals(wifiInfo.getMacAddress(), connectionInfo.getMacAddress());
2671     }
2672 
2673     /**
2674      * Test that reconnectCommand() triggers connectivity scan when ClientModeImpl
2675      * is in DisconnectedMode.
2676      */
2677     @Test
testReconnectCommandWhenDisconnected()2678     public void testReconnectCommandWhenDisconnected() throws Exception {
2679         // Connect to network with |TEST_BSSID_STR|, |sFreq|, and then disconnect.
2680         disconnect();
2681 
2682         mCmi.reconnect(ClientModeImpl.WIFI_WORK_SOURCE);
2683         mLooper.dispatchAll();
2684         verify(mWifiConnectivityManager).forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
2685     }
2686 
2687     /**
2688      * Test that reconnectCommand() doesn't trigger connectivity scan when ClientModeImpl
2689      * is in ConnectedMode.
2690      */
2691     @Test
testReconnectCommandWhenConnected()2692     public void testReconnectCommandWhenConnected() throws Exception {
2693         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
2694         connect();
2695 
2696         mCmi.reconnect(ClientModeImpl.WIFI_WORK_SOURCE);
2697         mLooper.dispatchAll();
2698         verify(mWifiConnectivityManager, never())
2699                 .forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
2700     }
2701 
2702     /**
2703      * Verifies that ClientModeImpl sets and unsets appropriate 'RecentFailureReason' values
2704      * on a WifiConfiguration when it fails association, authentication, or successfully connects
2705      */
2706     @Test
testExtraFailureReason_ApIsBusy()2707     public void testExtraFailureReason_ApIsBusy() throws Exception {
2708         // Setup CONNECT_MODE & a WifiConfiguration
2709         initializeAndAddNetworkAndVerifySuccess();
2710         // Trigger a connection to this (CMD_START_CONNECT will actually fail, but it sets up
2711         // targetNetworkId state)
2712         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
2713         mLooper.dispatchAll();
2714         // Simulate an ASSOCIATION_REJECTION_EVENT, due to the AP being busy
2715         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
2716                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR,
2717                         ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA,
2718                         false));
2719         mLooper.dispatchAll();
2720         verify(mWifiConfigManager).setRecentFailureAssociationStatus(eq(0),
2721                 eq(WifiConfiguration.RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA));
2722         assertEquals("DisconnectedState", getCurrentState().getName());
2723 
2724         // Simulate an AUTHENTICATION_FAILURE_EVENT, which should clear the ExtraFailureReason
2725         reset(mWifiConfigManager);
2726         initializeAndAddNetworkAndVerifySuccess();
2727         // Trigger a connection to this (CMD_START_CONNECT will actually fail, but it sets up
2728         // targetNetworkId state)
2729         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
2730         mLooper.dispatchAll();
2731         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0, 0, null);
2732         DisconnectEventInfo disconnectEventInfo =
2733                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
2734         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
2735         mLooper.dispatchAll();
2736         verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
2737         verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
2738 
2739         // Simulate a NETWORK_CONNECTION_EVENT which should clear the ExtraFailureReason
2740         reset(mWifiConfigManager);
2741         initializeAndAddNetworkAndVerifySuccess();
2742         // Trigger a connection to this (CMD_START_CONNECT will actually fail, but it sets up
2743         // targetNetworkId state)
2744         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
2745         mLooper.dispatchAll();
2746         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
2747                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, null, false));
2748         mLooper.dispatchAll();
2749         verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
2750         verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
2751     }
2752 
makeLastSelectedWifiConfiguration(int lastSelectedNetworkId, long timeSinceLastSelected)2753     private WifiConfiguration makeLastSelectedWifiConfiguration(int lastSelectedNetworkId,
2754             long timeSinceLastSelected) {
2755         long lastSelectedTimestamp = 45666743454L;
2756 
2757         when(mClock.getElapsedSinceBootMillis()).thenReturn(
2758                 lastSelectedTimestamp + timeSinceLastSelected);
2759         when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(lastSelectedTimestamp);
2760         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(lastSelectedNetworkId);
2761 
2762         WifiConfiguration currentConfig = new WifiConfiguration();
2763         currentConfig.networkId = lastSelectedNetworkId;
2764         return currentConfig;
2765     }
2766 
2767     /**
2768      * Test that the helper method
2769      * {@link ClientModeImpl#isRecentlySelectedByTheUser(WifiConfiguration)}
2770      * returns true when we connect to the last selected network before expiration of
2771      * {@link ClientModeImpl#LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS}.
2772      */
2773     @Test
testIsRecentlySelectedByTheUser_SameNetworkNotExpired()2774     public void testIsRecentlySelectedByTheUser_SameNetworkNotExpired() {
2775         WifiConfiguration currentConfig = makeLastSelectedWifiConfiguration(5,
2776                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2777         assertTrue(mCmi.isRecentlySelectedByTheUser(currentConfig));
2778     }
2779 
2780     /**
2781      * Test that the helper method
2782      * {@link ClientModeImpl#isRecentlySelectedByTheUser(WifiConfiguration)}
2783      * returns false when we connect to the last selected network after expiration of
2784      * {@link ClientModeImpl#LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS}.
2785      */
2786     @Test
testIsRecentlySelectedByTheUser_SameNetworkExpired()2787     public void testIsRecentlySelectedByTheUser_SameNetworkExpired() {
2788         WifiConfiguration currentConfig = makeLastSelectedWifiConfiguration(5,
2789                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS + 1);
2790         assertFalse(mCmi.isRecentlySelectedByTheUser(currentConfig));
2791     }
2792 
2793     /**
2794      * Test that the helper method
2795      * {@link ClientModeImpl#isRecentlySelectedByTheUser(WifiConfiguration)}
2796      * returns false when we connect to a different network to the last selected network.
2797      */
2798     @Test
testIsRecentlySelectedByTheUser_DifferentNetwork()2799     public void testIsRecentlySelectedByTheUser_DifferentNetwork() {
2800         WifiConfiguration currentConfig = makeLastSelectedWifiConfiguration(5,
2801                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2802         currentConfig.networkId = 4;
2803         assertFalse(mCmi.isRecentlySelectedByTheUser(currentConfig));
2804     }
2805 
expectRegisterNetworkAgent(Consumer<NetworkAgentConfig> configChecker, Consumer<NetworkCapabilities> networkCapabilitiesChecker)2806     private void expectRegisterNetworkAgent(Consumer<NetworkAgentConfig> configChecker,
2807             Consumer<NetworkCapabilities> networkCapabilitiesChecker) {
2808         // Expects that the code calls registerNetworkAgent and provides a way for the test to
2809         // verify the messages sent through the NetworkAgent to ConnectivityService.
2810         // We cannot just use a mock object here because mWifiNetworkAgent is private to CMI.
2811         ArgumentCaptor<NetworkAgentConfig> configCaptor =
2812                 ArgumentCaptor.forClass(NetworkAgentConfig.class);
2813         ArgumentCaptor<NetworkCapabilities> networkCapabilitiesCaptor =
2814                 ArgumentCaptor.forClass(NetworkCapabilities.class);
2815 
2816         verify(mWifiInjector).makeWifiNetworkAgent(
2817                 networkCapabilitiesCaptor.capture(),
2818                 any(),
2819                 configCaptor.capture(),
2820                 any(),
2821                 mWifiNetworkAgentCallbackCaptor.capture());
2822 
2823         configChecker.accept(configCaptor.getValue());
2824         networkCapabilitiesChecker.accept(networkCapabilitiesCaptor.getValue());
2825     }
2826 
expectNetworkAgentUpdateCapabilities( Consumer<NetworkCapabilities> networkCapabilitiesChecker)2827     private void expectNetworkAgentUpdateCapabilities(
2828             Consumer<NetworkCapabilities> networkCapabilitiesChecker) throws Exception {
2829         ArgumentCaptor<NetworkCapabilities> captor = ArgumentCaptor.forClass(
2830                 NetworkCapabilities.class);
2831         mLooper.dispatchAll();
2832         verify(mWifiNetworkAgent).sendNetworkCapabilitiesAndCache(captor.capture());
2833         networkCapabilitiesChecker.accept(captor.getValue());
2834     }
2835 
2836     /**
2837      * Verify that when a network is explicitly selected, but noInternetAccessExpected is false,
2838      * the {@link NetworkAgentConfig} contains the right values of explicitlySelected,
2839      * acceptUnvalidated and acceptPartialConnectivity.
2840      */
2841     @Test
testExplicitlySelected_ExplicitInternetExpected()2842     public void testExplicitlySelected_ExplicitInternetExpected() throws Exception {
2843         // Network is explicitly selected.
2844         WifiConfiguration config = makeLastSelectedWifiConfiguration(FRAMEWORK_NETWORK_ID,
2845                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2846         mConnectedNetwork.noInternetAccessExpected = false;
2847 
2848         connect();
2849         expectRegisterNetworkAgent((agentConfig) -> {
2850             assertTrue(agentConfig.explicitlySelected);
2851             assertFalse(agentConfig.acceptUnvalidated);
2852             assertFalse(agentConfig.acceptPartialConnectivity);
2853         }, (cap) -> { });
2854     }
2855 
2856     /**
2857      * Verify that when a network is explicitly selected, has role SECONDARY_TRANSIENT, but
2858      * noInternetAccessExpected is false, the {@link NetworkAgentConfig} contains the right values
2859      * of explicitlySelected, acceptUnvalidated and acceptPartialConnectivity.
2860      */
2861     @Test
testExplicitlySelected_secondaryTransient_expectNotExplicitlySelected()2862     public void testExplicitlySelected_secondaryTransient_expectNotExplicitlySelected()
2863             throws Exception {
2864         // Network is explicitly selected.
2865         WifiConfiguration config = makeLastSelectedWifiConfiguration(FRAMEWORK_NETWORK_ID,
2866                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2867         mConnectedNetwork.noInternetAccessExpected = false;
2868 
2869         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
2870 
2871         connect();
2872         expectRegisterNetworkAgent((agentConfig) -> {
2873             assertFalse(agentConfig.explicitlySelected);
2874             assertFalse(agentConfig.acceptUnvalidated);
2875             assertFalse(agentConfig.acceptPartialConnectivity);
2876         }, (cap) -> { });
2877     }
2878 
2879     /**
2880      * Verify that when a network is not explicitly selected, but noInternetAccessExpected is true,
2881      * the {@link NetworkAgentConfig} contains the right values of explicitlySelected,
2882      * acceptUnvalidated and acceptPartialConnectivity.
2883      */
2884     @Test
testExplicitlySelected_NotExplicitNoInternetExpected()2885     public void testExplicitlySelected_NotExplicitNoInternetExpected() throws Exception {
2886         // Network is no longer explicitly selected.
2887         WifiConfiguration config = makeLastSelectedWifiConfiguration(FRAMEWORK_NETWORK_ID,
2888                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS + 1);
2889         mConnectedNetwork.noInternetAccessExpected = true;
2890 
2891         connect();
2892         expectRegisterNetworkAgent((agentConfig) -> {
2893             assertFalse(agentConfig.explicitlySelected);
2894             assertFalse(agentConfig.acceptUnvalidated);
2895             assertTrue(agentConfig.acceptPartialConnectivity);
2896         }, (cap) -> { });
2897     }
2898 
2899     /**
2900      * Verify that when a network is explicitly selected, and noInternetAccessExpected is true,
2901      * the {@link NetworkAgentConfig} contains the right values of explicitlySelected,
2902      * acceptUnvalidated and acceptPartialConnectivity.
2903      */
2904     @Test
testExplicitlySelected_ExplicitNoInternetExpected()2905     public void testExplicitlySelected_ExplicitNoInternetExpected() throws Exception {
2906         // Network is explicitly selected.
2907         WifiConfiguration config = makeLastSelectedWifiConfiguration(FRAMEWORK_NETWORK_ID,
2908                 ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS - 1);
2909         mConnectedNetwork.noInternetAccessExpected = true;
2910 
2911         connect();
2912         expectRegisterNetworkAgent((agentConfig) -> {
2913             assertTrue(agentConfig.explicitlySelected);
2914             assertTrue(agentConfig.acceptUnvalidated);
2915             assertTrue(agentConfig.acceptPartialConnectivity);
2916         }, (cap) -> { });
2917     }
2918 
2919     /**
2920      * Verify that Rssi Monitoring is started and the callback registered after connecting.
2921      */
2922     @Test
verifyRssiMonitoringCallbackIsRegistered()2923     public void verifyRssiMonitoringCallbackIsRegistered() throws Exception {
2924         // Simulate the first connection.
2925         connect();
2926 
2927         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
2928                 mWifiNetworkAgentCallbackCaptor.capture());
2929 
2930         ArrayList<Integer> thresholdsArray = new ArrayList<>();
2931         thresholdsArray.add(RSSI_THRESHOLD_MAX);
2932         thresholdsArray.add(RSSI_THRESHOLD_MIN);
2933         mWifiNetworkAgentCallbackCaptor.getValue().onSignalStrengthThresholdsUpdated(
2934                 thresholdsArray.stream().mapToInt(Integer::intValue).toArray());
2935         mLooper.dispatchAll();
2936 
2937         ArgumentCaptor<WifiNative.WifiRssiEventHandler> rssiEventHandlerCaptor =
2938                 ArgumentCaptor.forClass(WifiNative.WifiRssiEventHandler.class);
2939         verify(mWifiNative).startRssiMonitoring(anyString(), anyByte(), anyByte(),
2940                 rssiEventHandlerCaptor.capture());
2941 
2942         // breach below min
2943         rssiEventHandlerCaptor.getValue().onRssiThresholdBreached(RSSI_THRESHOLD_BREACH_MIN);
2944         mLooper.dispatchAll();
2945         WifiInfo wifiInfo = mWifiInfo;
2946         assertEquals(RSSI_THRESHOLD_BREACH_MIN, wifiInfo.getRssi());
2947 
2948         // breach above max
2949         rssiEventHandlerCaptor.getValue().onRssiThresholdBreached(RSSI_THRESHOLD_BREACH_MAX);
2950         mLooper.dispatchAll();
2951         assertEquals(RSSI_THRESHOLD_BREACH_MAX, wifiInfo.getRssi());
2952     }
2953 
2954     /**
2955      * Verify that RSSI and link layer stats polling works in connected mode
2956      */
2957     @Test
verifyConnectedModeRssiPolling()2958     public void verifyConnectedModeRssiPolling() throws Exception {
2959         final long startMillis = 1_500_000_000_100L;
2960         WifiLinkLayerStats llStats = new WifiLinkLayerStats();
2961         llStats.txmpdu_be = 1000;
2962         llStats.rxmpdu_bk = 2000;
2963         WifiNl80211Manager.SignalPollResult signalPollResult =
2964                 new WifiNl80211Manager.SignalPollResult(-42, 65, 54, sFreq);
2965         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(llStats);
2966         when(mWifiNative.signalPoll(any())).thenReturn(signalPollResult);
2967         when(mClock.getWallClockMillis()).thenReturn(startMillis + 0);
2968         mCmi.enableRssiPolling(true);
2969         connect();
2970         mLooper.dispatchAll();
2971         when(mClock.getWallClockMillis()).thenReturn(startMillis + 3333);
2972         mLooper.dispatchAll();
2973         WifiInfo wifiInfo = mWifiInfo;
2974         assertEquals(llStats.txmpdu_be, wifiInfo.txSuccess);
2975         assertEquals(llStats.rxmpdu_bk, wifiInfo.rxSuccess);
2976         assertEquals(signalPollResult.currentRssiDbm, wifiInfo.getRssi());
2977         assertEquals(signalPollResult.txBitrateMbps, wifiInfo.getLinkSpeed());
2978         assertEquals(signalPollResult.txBitrateMbps, wifiInfo.getTxLinkSpeedMbps());
2979         assertEquals(signalPollResult.rxBitrateMbps, wifiInfo.getRxLinkSpeedMbps());
2980         assertEquals(sFreq, wifiInfo.getFrequency());
2981         verify(mPerNetwork, atLeastOnce()).getTxLinkBandwidthKbps();
2982         verify(mPerNetwork, atLeastOnce()).getRxLinkBandwidthKbps();
2983         verify(mWifiScoreCard).noteSignalPoll(any());
2984     }
2985 
2986     /**
2987      * Verify link bandwidth update in connected mode
2988      */
2989     @Test
verifyConnectedModeNetworkCapabilitiesBandwidthUpdate()2990     public void verifyConnectedModeNetworkCapabilitiesBandwidthUpdate() throws Exception {
2991         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(40_000);
2992         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(50_000);
2993         when(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName(any(), any()))
2994                 .thenReturn(Pair.create(Process.INVALID_UID, ""));
2995         // Simulate the first connection.
2996         connectWithValidInitRssi(-42);
2997 
2998         // NetworkCapabilities should be always updated after the connection
2999         ArgumentCaptor<NetworkCapabilities> networkCapabilitiesCaptor =
3000                 ArgumentCaptor.forClass(NetworkCapabilities.class);
3001         verify(mWifiInjector).makeWifiNetworkAgent(
3002                 networkCapabilitiesCaptor.capture(), any(), any(), any(), any());
3003         NetworkCapabilities networkCapabilities = networkCapabilitiesCaptor.getValue();
3004         assertNotNull(networkCapabilities);
3005         assertEquals(-42, mWifiInfo.getRssi());
3006         assertEquals(40_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
3007         assertEquals(50_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
3008         verify(mCmi.mNetworkAgent, times(2))
3009                 .sendNetworkCapabilitiesAndCache(networkCapabilitiesCaptor.capture());
3010 
3011         // Enable RSSI polling
3012         final long startMillis = 1_500_000_000_100L;
3013         WifiLinkLayerStats llStats = new WifiLinkLayerStats();
3014         WifiNl80211Manager.SignalPollResult signalPollResult =
3015                 new WifiNl80211Manager.SignalPollResult(-42, 65, 54, sFreq);
3016         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(llStats);
3017         when(mWifiNative.signalPoll(any())).thenReturn(signalPollResult);
3018         when(mClock.getWallClockMillis()).thenReturn(startMillis + 0);
3019         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(82_000);
3020         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(92_000);
3021         mCmi.enableRssiPolling(true);
3022         mLooper.dispatchAll();
3023         when(mClock.getWallClockMillis()).thenReturn(startMillis + 3333);
3024         mLooper.dispatchAll();
3025 
3026         // NetworkCapabilities should be updated after a big change of bandwidth
3027         verify(mCmi.mNetworkAgent, times(3))
3028                 .sendNetworkCapabilitiesAndCache(networkCapabilitiesCaptor.capture());
3029         networkCapabilities = networkCapabilitiesCaptor.getValue();
3030         assertEquals(82_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
3031         assertEquals(92_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
3032 
3033         // No update after a small change of bandwidth
3034         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(72_000);
3035         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(82_000);
3036         when(mClock.getWallClockMillis()).thenReturn(startMillis + 3333);
3037         mLooper.dispatchAll();
3038         verify(mCmi.mNetworkAgent, times(3))
3039                 .sendNetworkCapabilitiesAndCache(networkCapabilitiesCaptor.capture());
3040         networkCapabilities = networkCapabilitiesCaptor.getValue();
3041         assertEquals(82_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
3042         assertEquals(92_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
3043     }
3044 
3045     /**
3046      * Verify RSSI polling with verbose logging
3047      */
3048     @Test
verifyConnectedModeRssiPollingWithVerboseLogging()3049     public void verifyConnectedModeRssiPollingWithVerboseLogging() throws Exception {
3050         mCmi.enableVerboseLogging(true);
3051         verifyConnectedModeRssiPolling();
3052     }
3053 
3054     /**
3055      * Verify that calls to start and stop filtering multicast packets are passed on to the IpClient
3056      * instance.
3057      */
3058     @Test
verifyMcastLockManagerFilterControllerCallsUpdateIpClient()3059     public void verifyMcastLockManagerFilterControllerCallsUpdateIpClient() throws Exception {
3060         reset(mIpClient);
3061         WifiMulticastLockManager.FilterController filterController =
3062                 mCmi.getMcastLockManagerFilterController();
3063         filterController.startFilteringMulticastPackets();
3064         verify(mIpClient).setMulticastFilter(eq(true));
3065         filterController.stopFilteringMulticastPackets();
3066         verify(mIpClient).setMulticastFilter(eq(false));
3067     }
3068 
3069     /**
3070      * Verifies that when
3071      * 1. Global feature support flag is set to false
3072      * 2. connected MAC randomization is on and
3073      * 3. macRandomizationSetting of the WifiConfiguration is RANDOMIZATION_AUTO and
3074      * 4. randomized MAC for the network to connect to is different from the current MAC.
3075      *
3076      * The factory MAC address is used for the connection, and no attempt is made to change it.
3077      */
3078     @Test
testConnectedMacRandomizationNotSupported()3079     public void testConnectedMacRandomizationNotSupported() throws Exception {
3080         // reset mWifiNative since initializeCmi() was called in setup()
3081         resetWifiNative();
3082 
3083         when(mWifiGlobals.isConnectedMacRandomizationEnabled()).thenReturn(false);
3084         initializeCmi();
3085         initializeAndAddNetworkAndVerifySuccess();
3086 
3087         connect();
3088         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3089         verify(mWifiNative, never()).setStaMacAddress(any(), any());
3090         // try to retrieve factory MAC address (once at bootup, once for this connection)
3091         verify(mSettingsConfigStore, times(2)).get(any());
3092     }
3093 
3094     /**
3095      * Verifies that when
3096      * 1. connected MAC randomization is on and
3097      * 2. macRandomizationSetting of the WifiConfiguration is RANDOMIZATION_AUTO and
3098      * 3. randomized MAC for the network to connect to is different from the current MAC.
3099      *
3100      * Then the current MAC gets set to the randomized MAC when CMD_START_CONNECT executes.
3101      */
3102     @Test
testConnectedMacRandomizationRandomizationPersistentDifferentMac()3103     public void testConnectedMacRandomizationRandomizationPersistentDifferentMac()
3104             throws Exception {
3105         initializeAndAddNetworkAndVerifySuccess();
3106 
3107         connect();
3108         verify(mWifiNative).setStaMacAddress(WIFI_IFACE_NAME, TEST_LOCAL_MAC_ADDRESS);
3109         verify(mWifiMetrics).logStaEvent(
3110                 eq(WIFI_IFACE_NAME), eq(StaEvent.TYPE_MAC_CHANGE), any(WifiConfiguration.class));
3111         assertEquals(TEST_LOCAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3112     }
3113 
3114     /**
3115      * Verifies that when
3116      * 1. connected MAC randomization is on and
3117      * 2. macRandomizationSetting of the WifiConfiguration is RANDOMIZATION_AUTO and
3118      * 3. randomized MAC for the network to connect to is same as the current MAC.
3119      *
3120      * Then MAC change should not occur when CMD_START_CONNECT executes.
3121      */
3122     @Test
testConnectedMacRandomizationRandomizationPersistentSameMac()3123     public void testConnectedMacRandomizationRandomizationPersistentSameMac() throws Exception {
3124         initializeAndAddNetworkAndVerifySuccess();
3125 
3126         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
3127                 .thenReturn(TEST_LOCAL_MAC_ADDRESS.toString());
3128 
3129         connect();
3130         verify(mWifiNative, never()).setStaMacAddress(WIFI_IFACE_NAME, TEST_LOCAL_MAC_ADDRESS);
3131         verify(mWifiMetrics, never()).logStaEvent(
3132                 any(), eq(StaEvent.TYPE_MAC_CHANGE), any(WifiConfiguration.class));
3133         assertEquals(TEST_LOCAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3134     }
3135 
3136     /**
3137      * Verifies that when
3138      * 1. connected MAC randomization is on and
3139      * 2. macRandomizationSetting of the WifiConfiguration is RANDOMIZATION_NONE and
3140      * 3. current MAC address is not the factory MAC.
3141      *
3142      * Then the current MAC gets set to the factory MAC when CMD_START_CONNECT executes.
3143      * @throws Exception
3144      */
3145     @Test
testConnectedMacRandomizationRandomizationNoneDifferentMac()3146     public void testConnectedMacRandomizationRandomizationNoneDifferentMac() throws Exception {
3147         initializeAndAddNetworkAndVerifySuccess();
3148 
3149         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
3150                 .thenReturn(TEST_LOCAL_MAC_ADDRESS.toString());
3151 
3152         WifiConfiguration config = new WifiConfiguration();
3153         config.SSID = TEST_SSID;
3154         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
3155         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
3156         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(0)).thenReturn(config);
3157 
3158         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3159         mLooper.dispatchAll();
3160 
3161         verify(mWifiNative).setStaMacAddress(WIFI_IFACE_NAME, TEST_GLOBAL_MAC_ADDRESS);
3162         verify(mWifiMetrics).logStaEvent(
3163                 eq(WIFI_IFACE_NAME), eq(StaEvent.TYPE_MAC_CHANGE), any(WifiConfiguration.class));
3164         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3165     }
3166 
3167     /**
3168      * Verifies that when
3169      * 1. connected MAC randomization is on and
3170      * 2. macRandomizationSetting of the WifiConfiguration is RANDOMIZATION_NONE and
3171      *
3172      * Then the factory MAC should be used to connect to the network.
3173      * @throws Exception
3174      */
3175     @Test
testConnectedMacRandomizationRandomizationNoneSameMac()3176     public void testConnectedMacRandomizationRandomizationNoneSameMac() throws Exception {
3177         initializeAndAddNetworkAndVerifySuccess();
3178 
3179         clearInvocations(mWifiNative, mSettingsConfigStore);
3180 
3181         WifiConfiguration config = new WifiConfiguration();
3182         config.SSID = TEST_SSID;
3183         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
3184         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
3185         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(0)).thenReturn(config);
3186 
3187         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3188         mLooper.dispatchAll();
3189 
3190         verify(mSettingsConfigStore).get(WIFI_STA_FACTORY_MAC_ADDRESS);
3191         verify(mWifiNative, never()).getStaFactoryMacAddress(WIFI_IFACE_NAME);
3192         verify(mSettingsConfigStore, never()).put(
3193                 WIFI_STA_FACTORY_MAC_ADDRESS, TEST_GLOBAL_MAC_ADDRESS.toString());
3194 
3195         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3196 
3197         // Now disconnect & reconnect - should use the cached factory MAC address.
3198         mCmi.disconnect();
3199         mLooper.dispatchAll();
3200 
3201         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3202         mLooper.dispatchAll();
3203 
3204         verify(mSettingsConfigStore, times(2)).get(WIFI_STA_FACTORY_MAC_ADDRESS);
3205         // No new call to retrieve & store factory MAC address.
3206         verify(mWifiNative, never()).getStaFactoryMacAddress(WIFI_IFACE_NAME);
3207         verify(mSettingsConfigStore, never()).put(
3208                 WIFI_STA_FACTORY_MAC_ADDRESS, TEST_GLOBAL_MAC_ADDRESS.toString());
3209     }
3210 
3211     /**
3212      * Verifies that WifiInfo returns DEFAULT_MAC_ADDRESS as mac address when Connected MAC
3213      * Randomization is on and the device is not connected to a wifi network.
3214      */
3215     @Test
testWifiInfoReturnDefaultMacWhenDisconnectedWithRandomization()3216     public void testWifiInfoReturnDefaultMacWhenDisconnectedWithRandomization() throws Exception {
3217         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
3218                 .thenReturn(TEST_LOCAL_MAC_ADDRESS.toString());
3219 
3220         connect();
3221         assertEquals(TEST_LOCAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3222 
3223         DisconnectEventInfo disconnectEventInfo =
3224                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
3225         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
3226         mLooper.dispatchAll();
3227         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
3228                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
3229                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
3230         mLooper.dispatchAll();
3231 
3232         assertEquals("DisconnectedState", getCurrentState().getName());
3233         assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mWifiInfo.getMacAddress());
3234         assertFalse(mWifiInfo.hasRealMacAddress());
3235     }
3236 
3237     /**
3238      * Verifies that we don't set MAC address when config returns an invalid MAC address.
3239      */
3240     @Test
testDoNotSetMacWhenInvalid()3241     public void testDoNotSetMacWhenInvalid() throws Exception {
3242         initializeAndAddNetworkAndVerifySuccess();
3243 
3244         WifiConfiguration config = new WifiConfiguration();
3245         config.SSID = TEST_SSID;
3246         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
3247         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
3248         config.setRandomizedMacAddress(MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS));
3249         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(0)).thenReturn(config);
3250 
3251         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3252         mLooper.dispatchAll();
3253 
3254         // setStaMacAddress is invoked once when ClientModeImpl starts to prevent leak of factory
3255         // MAC.
3256         verify(mWifiNative).setStaMacAddress(eq(WIFI_IFACE_NAME), any(MacAddress.class));
3257     }
3258 
3259     /**
3260      * Verify that we don't crash when WifiNative returns null as the current MAC address.
3261      * @throws Exception
3262      */
3263     @Test
testMacRandomizationWifiNativeReturningNull()3264     public void testMacRandomizationWifiNativeReturningNull() throws Exception {
3265         when(mWifiNative.getMacAddress(anyString())).thenReturn(null);
3266         initializeAndAddNetworkAndVerifySuccess();
3267 
3268         connect();
3269         verify(mWifiNative).setStaMacAddress(WIFI_IFACE_NAME, TEST_LOCAL_MAC_ADDRESS);
3270     }
3271 
3272     /**
3273      * Verifies that a notification is posted when a connection failure happens on a network
3274      * in the hotlist. Then verify that tapping on the notification launches an dialog, which
3275      * could be used to set the randomization setting for a network to "Trusted".
3276      */
3277     @Test
testConnectionFailureSendRandomizationSettingsNotification()3278     public void testConnectionFailureSendRandomizationSettingsNotification() throws Exception {
3279         when(mWifiConfigManager.isInFlakyRandomizationSsidHotlist(anyInt())).thenReturn(true);
3280         // Setup CONNECT_MODE & a WifiConfiguration
3281         initializeAndAddNetworkAndVerifySuccess();
3282         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, FRAMEWORK_NETWORK_ID, 0, TEST_BSSID_STR);
3283         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3284                 WifiManager.ERROR_AUTH_FAILURE_TIMEOUT);
3285         mLooper.dispatchAll();
3286 
3287         WifiConfiguration config = mCmi.getConnectedWifiConfiguration();
3288         verify(mConnectionFailureNotifier)
3289                 .showFailedToConnectDueToNoRandomizedMacSupportNotification(FRAMEWORK_NETWORK_ID);
3290     }
3291 
3292     /**
3293      * Verifies that a notification is not posted when a wrong password failure happens on a
3294      * network in the hotlist.
3295      */
3296     @Test
testNotCallingIsInFlakyRandomizationSsidHotlistOnWrongPassword()3297     public void testNotCallingIsInFlakyRandomizationSsidHotlistOnWrongPassword() throws Exception {
3298         when(mWifiConfigManager.isInFlakyRandomizationSsidHotlist(anyInt())).thenReturn(true);
3299         // Setup CONNECT_MODE & a WifiConfiguration
3300         initializeAndAddNetworkAndVerifySuccess();
3301         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, FRAMEWORK_NETWORK_ID, 0, TEST_BSSID_STR);
3302         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3303                 WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
3304         mLooper.dispatchAll();
3305 
3306         verify(mConnectionFailureNotifier, never())
3307                 .showFailedToConnectDueToNoRandomizedMacSupportNotification(anyInt());
3308     }
3309 
3310     /**
3311      * Verifies that CMD_START_CONNECT make WifiDiagnostics report
3312      * CONNECTION_EVENT_STARTED
3313      * @throws Exception
3314      */
3315     @Test
testReportConnectionEventIsCalledAfterCmdStartConnect()3316     public void testReportConnectionEventIsCalledAfterCmdStartConnect() throws Exception {
3317         // Setup CONNECT_MODE & a WifiConfiguration
3318         initializeAndAddNetworkAndVerifySuccess();
3319         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3320         verify(mWifiDiagnostics, never()).reportConnectionEvent(
3321                 eq(WifiDiagnostics.CONNECTION_EVENT_STARTED), any());
3322         mLooper.dispatchAll();
3323         verify(mWifiDiagnostics).reportConnectionEvent(
3324                 eq(WifiDiagnostics.CONNECTION_EVENT_STARTED), any());
3325     }
3326 
3327     /**
3328      * Verifies that CMD_DIAG_CONNECT_TIMEOUT is processed after the timeout threshold if we
3329      * start a connection but do not finish it.
3330      * @throws Exception
3331      */
3332     @Test
testCmdDiagsConnectTimeoutIsGeneratedAfterCmdStartConnect()3333     public void testCmdDiagsConnectTimeoutIsGeneratedAfterCmdStartConnect() throws Exception {
3334         // Setup CONNECT_MODE & a WifiConfiguration
3335         initializeAndAddNetworkAndVerifySuccess();
3336         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3337         mLooper.dispatchAll();
3338         mLooper.moveTimeForward(ClientModeImpl.DIAGS_CONNECT_TIMEOUT_MILLIS);
3339         mLooper.dispatchAll();
3340         verify(mWifiDiagnostics).reportConnectionEvent(
3341                 eq(WifiDiagnostics.CONNECTION_EVENT_TIMEOUT), any());
3342     }
3343 
3344     /**
3345      * Verifies that CMD_DIAG_CONNECT_TIMEOUT does not get processed before the timeout threshold.
3346      * @throws Exception
3347      */
3348     @Test
testCmdDiagsConnectTimeoutIsNotProcessedBeforeTimerExpires()3349     public void testCmdDiagsConnectTimeoutIsNotProcessedBeforeTimerExpires() throws Exception {
3350         // Setup CONNECT_MODE & a WifiConfiguration
3351         initializeAndAddNetworkAndVerifySuccess();
3352         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3353         mLooper.dispatchAll();
3354         mLooper.moveTimeForward(ClientModeImpl.DIAGS_CONNECT_TIMEOUT_MILLIS - 1000);
3355         mLooper.dispatchAll();
3356         verify(mWifiDiagnostics, never()).reportConnectionEvent(
3357                 eq(WifiDiagnostics.CONNECTION_EVENT_TIMEOUT), any());
3358     }
3359 
verifyConnectionEventTimeoutDoesNotOccur()3360     private void verifyConnectionEventTimeoutDoesNotOccur() {
3361         mLooper.moveTimeForward(ClientModeImpl.DIAGS_CONNECT_TIMEOUT_MILLIS);
3362         mLooper.dispatchAll();
3363         verify(mWifiDiagnostics, never()).reportConnectionEvent(
3364                 eq(WifiDiagnostics.CONNECTION_EVENT_TIMEOUT), any());
3365     }
3366 
3367     /**
3368      * Verifies that association failures make WifiDiagnostics report CONNECTION_EVENT_FAILED
3369      * and then cancel any pending timeouts.
3370      * Also, send connection status to {@link WifiNetworkFactory} & {@link WifiConnectivityManager}.
3371      * @throws Exception
3372      */
3373     @Test
testReportConnectionEventIsCalledAfterAssociationFailure()3374     public void testReportConnectionEventIsCalledAfterAssociationFailure() throws Exception {
3375         mConnectedNetwork.getNetworkSelectionStatus()
3376                 .setCandidate(getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq)
3377                         .getScanResult());
3378         // Setup CONNECT_MODE & a WifiConfiguration
3379         initializeAndAddNetworkAndVerifySuccess();
3380         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3381         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3382                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR,
3383                         ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, false));
3384         verify(mWifiDiagnostics, never()).reportConnectionEvent(
3385                 eq(WifiDiagnostics.CONNECTION_EVENT_FAILED), any());
3386         mLooper.dispatchAll();
3387         verify(mWifiDiagnostics).reportConnectionEvent(
3388                 eq(WifiDiagnostics.CONNECTION_EVENT_FAILED), any());
3389         verify(mWifiConnectivityManager).handleConnectionAttemptEnded(
3390                 mClientModeManager,
3391                 WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, TEST_BSSID_STR,
3392                 TEST_SSID);
3393         verify(mWifiNetworkFactory).handleConnectionAttemptEnded(
3394                 eq(WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION),
3395                 any(WifiConfiguration.class), eq(TEST_BSSID_STR));
3396         verify(mWifiNetworkSuggestionsManager).handleConnectionAttemptEnded(
3397                 eq(WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION),
3398                 any(WifiConfiguration.class), eq(null));
3399         verify(mWifiMetrics, never())
3400                 .incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3401         verifyConnectionEventTimeoutDoesNotOccur();
3402 
3403         clearInvocations(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
3404                 mWifiNetworkSuggestionsManager);
3405 
3406         // Now trigger a disconnect event from supplicant, this should be ignored since the
3407         // connection tracking should have already ended.
3408         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT,
3409                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false));
3410         mLooper.dispatchAll();
3411 
3412         verifyNoMoreInteractions(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
3413                 mWifiNetworkSuggestionsManager);
3414     }
3415 
3416     /**
3417      * Verifies that authentication failures make WifiDiagnostics report
3418      * CONNECTION_EVENT_FAILED and then cancel any pending timeouts.
3419      * Also, send connection status to {@link WifiNetworkFactory} & {@link WifiConnectivityManager}.
3420      * @throws Exception
3421      */
3422     @Test
testReportConnectionEventIsCalledAfterAuthenticationFailure()3423     public void testReportConnectionEventIsCalledAfterAuthenticationFailure() throws Exception {
3424         mConnectedNetwork.getNetworkSelectionStatus()
3425                 .setCandidate(getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq)
3426                         .getScanResult());
3427         // Setup CONNECT_MODE & a WifiConfiguration
3428         initializeAndAddNetworkAndVerifySuccess();
3429         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3430         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3431                 WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
3432         mLooper.dispatchAll();
3433         verify(mWifiDiagnostics).reportConnectionEvent(
3434                 eq(WifiDiagnostics.CONNECTION_EVENT_FAILED), any());
3435         verify(mWifiConnectivityManager).handleConnectionAttemptEnded(
3436                 mClientModeManager,
3437                 WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, TEST_BSSID_STR,
3438                 TEST_SSID);
3439         verify(mWifiNetworkFactory).handleConnectionAttemptEnded(
3440                 eq(WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE),
3441                 any(WifiConfiguration.class), eq(TEST_BSSID_STR));
3442         verify(mWifiNetworkSuggestionsManager).handleConnectionAttemptEnded(
3443                 eq(WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE),
3444                 any(WifiConfiguration.class), eq(null));
3445         verify(mWifiMetrics, never())
3446                 .incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3447         verifyConnectionEventTimeoutDoesNotOccur();
3448 
3449         clearInvocations(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
3450                 mWifiNetworkSuggestionsManager);
3451 
3452         // Now trigger a disconnect event from supplicant, this should be ignored since the
3453         // connection tracking should have already ended.
3454         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT,
3455                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false));
3456         mLooper.dispatchAll();
3457 
3458         verifyNoMoreInteractions(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
3459                 mWifiNetworkSuggestionsManager);
3460     }
3461 
3462     /**
3463      * Verify that if a NETWORK_DISCONNECTION_EVENT is received in L3ConnectedState, then an
3464      * abnormal disconnect is reported to WifiBlocklistMonitor.
3465      */
3466     @Test
testAbnormalDisconnectNotifiesWifiBlocklistMonitor()3467     public void testAbnormalDisconnectNotifiesWifiBlocklistMonitor() throws Exception {
3468         // trigger RSSI poll to update WifiInfo
3469         mCmi.enableRssiPolling(true);
3470         WifiLinkLayerStats llStats = new WifiLinkLayerStats();
3471         llStats.txmpdu_be = 1000;
3472         llStats.rxmpdu_bk = 2000;
3473         WifiNl80211Manager.SignalPollResult signalPollResult =
3474                 new WifiNl80211Manager.SignalPollResult(TEST_RSSI, 65, 54, sFreq);
3475         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(llStats);
3476         when(mWifiNative.signalPoll(any())).thenReturn(signalPollResult);
3477 
3478         connect();
3479         mLooper.dispatchAll();
3480         DisconnectEventInfo disconnectEventInfo =
3481                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
3482         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
3483         mLooper.dispatchAll();
3484 
3485         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3486                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_ABNORMAL_DISCONNECT), anyInt());
3487     }
3488 
3489     /**
3490      * Verify that ClientModeImpl notifies WifiBlocklistMonitor correctly when the RSSI is
3491      * too low.
3492      */
3493     @Test
testNotifiesWifiBlocklistMonitorLowRssi()3494     public void testNotifiesWifiBlocklistMonitorLowRssi() throws Exception {
3495         int testLowRssi = -80;
3496         initializeAndAddNetworkAndVerifySuccess();
3497         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, FRAMEWORK_NETWORK_ID, 0,
3498                 ClientModeImpl.SUPPLICANT_BSSID_ANY);
3499         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3500                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, true));
3501         when(mWifiConfigManager.findScanRssi(eq(FRAMEWORK_NETWORK_ID), anyInt()))
3502                 .thenReturn(testLowRssi);
3503         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
3504                 .thenReturn(mScanDetailCache);
3505         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
3506                 getGoogleGuestScanDetail(testLowRssi, TEST_BSSID_STR, sFreq));
3507         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
3508                 getGoogleGuestScanDetail(testLowRssi, TEST_BSSID_STR, sFreq).getScanResult());
3509         mLooper.dispatchAll();
3510 
3511         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(TEST_BSSID_STR, TEST_SSID,
3512                 WifiBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT, testLowRssi);
3513     }
3514 
3515     /**
3516      * Verify that the recent failure association status is updated properly when
3517      * ASSOC_REJECTED_TEMPORARILY occurs.
3518      */
3519     @Test
testAssocRejectedTemporarilyUpdatesRecentAssociationFailureStatus()3520     public void testAssocRejectedTemporarilyUpdatesRecentAssociationFailureStatus()
3521             throws Exception {
3522         initializeAndAddNetworkAndVerifySuccess();
3523         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3524         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3525                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR,
3526                         ISupplicantStaIfaceCallback.StatusCode.ASSOC_REJECTED_TEMPORARILY,
3527                         false));
3528         mLooper.dispatchAll();
3529         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3530                 eq(WifiConfiguration.RECENT_FAILURE_REFUSED_TEMPORARILY));
3531     }
3532 
3533     /**
3534      * Verify that WifiScoreCard and WifiBlocklistMonitor are notified properly when
3535      * disconnection occurs in middle of connection states.
3536      */
3537     @Test
testDisconnectConnecting()3538     public void testDisconnectConnecting() throws Exception {
3539         initializeAndAddNetworkAndVerifySuccess();
3540         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3541         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT,
3542                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR,
3543                         ISupplicantStaIfaceCallback.ReasonCode.FOURWAY_HANDSHAKE_TIMEOUT,
3544                         false));
3545         mLooper.dispatchAll();
3546         verify(mWifiScoreCard).noteConnectionFailure(any(), anyInt(), anyString(), anyInt());
3547         verify(mWifiScoreCard).resetConnectionState(WIFI_IFACE_NAME);
3548         // Verify that the WifiBlocklistMonitor is notified of a non-locally generated disconnect
3549         // that occurred mid connection attempt.
3550         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(anyString(), anyString(),
3551                 eq(WifiBlocklistMonitor.REASON_NONLOCAL_DISCONNECT_CONNECTING), anyInt());
3552         verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(anyInt(),
3553                 eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_CONSECUTIVE_FAILURES));
3554     }
3555 
3556     /**
3557      * Verify that the WifiConfigManager is notified when a network experiences consecutive
3558      * connection failures.
3559      */
3560     @Test
testDisableNetworkConsecutiveFailures()3561     public void testDisableNetworkConsecutiveFailures() throws Exception {
3562         initializeAndAddNetworkAndVerifySuccess();
3563         when(mPerNetworkRecentStats.getCount(WifiScoreCard.CNT_CONSECUTIVE_CONNECTION_FAILURE))
3564                 .thenReturn(WifiBlocklistMonitor.NUM_CONSECUTIVE_FAILURES_PER_NETWORK_EXP_BACKOFF);
3565         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, FRAMEWORK_NETWORK_ID, 0, TEST_BSSID_STR);
3566         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT,
3567                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR,
3568                         ISupplicantStaIfaceCallback.ReasonCode.FOURWAY_HANDSHAKE_TIMEOUT,
3569                         false));
3570         mLooper.dispatchAll();
3571         verify(mWifiScoreCard).noteConnectionFailure(any(), anyInt(), anyString(), anyInt());
3572         verify(mWifiScoreCard).resetConnectionState(WIFI_IFACE_NAME);
3573         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(anyString(), anyString(),
3574                 eq(WifiBlocklistMonitor.REASON_NONLOCAL_DISCONNECT_CONNECTING), anyInt());
3575         verify(mWifiConfigManager).updateNetworkSelectionStatus(FRAMEWORK_NETWORK_ID,
3576                 WifiConfiguration.NetworkSelectionStatus.DISABLED_CONSECUTIVE_FAILURES);
3577     }
3578 
3579     /**
3580      * Verify that the recent failure association status is updated properly when
3581      * DENIED_POOR_CHANNEL_CONDITIONS occurs.
3582      */
3583     @Test
testAssocRejectedPoorChannelConditionsUpdatesRecentAssociationFailureStatus()3584     public void testAssocRejectedPoorChannelConditionsUpdatesRecentAssociationFailureStatus()
3585             throws Exception {
3586         initializeAndAddNetworkAndVerifySuccess();
3587         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3588         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3589                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR,
3590                         ISupplicantStaIfaceCallback.StatusCode.DENIED_POOR_CHANNEL_CONDITIONS,
3591                         false));
3592         mLooper.dispatchAll();
3593         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3594                 eq(WifiConfiguration.RECENT_FAILURE_POOR_CHANNEL_CONDITIONS));
3595     }
3596 
3597     /**
3598      * Verify that the recent failure association status is updated properly when a disconnection
3599      * with reason code DISASSOC_AP_BUSY occurs.
3600      */
3601     @Test
testNetworkDisconnectionApBusyUpdatesRecentAssociationFailureStatus()3602     public void testNetworkDisconnectionApBusyUpdatesRecentAssociationFailureStatus()
3603             throws Exception {
3604         connect();
3605         // Disconnection with reason = DISASSOC_AP_BUSY
3606         DisconnectEventInfo disconnectEventInfo =
3607                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 5, false);
3608         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
3609         mLooper.dispatchAll();
3610         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3611                 eq(WifiConfiguration.RECENT_FAILURE_DISCONNECTION_AP_BUSY));
3612     }
3613 
3614     /**
3615      * Verify that the recent failure association status is updated properly when a disconnection
3616      * with reason code DISASSOC_AP_BUSY occurs.
3617      */
3618     @Test
testMidConnectionDisconnectionApBusyUpdatesRecentAssociationFailureStatus()3619     public void testMidConnectionDisconnectionApBusyUpdatesRecentAssociationFailureStatus()
3620             throws Exception {
3621         initializeAndAddNetworkAndVerifySuccess();
3622         startConnectSuccess();
3623         assertEquals("L2ConnectingState", getCurrentState().getName());
3624 
3625         // Disconnection with reason = DISASSOC_AP_BUSY
3626         DisconnectEventInfo disconnectEventInfo =
3627                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 5, false);
3628         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
3629         mLooper.dispatchAll();
3630         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3631                 eq(WifiConfiguration.RECENT_FAILURE_DISCONNECTION_AP_BUSY));
3632     }
3633 
3634     /**
3635      * Verify that the recent failure association status is updated properly when
3636      * ASSOCIATION_REJECTION_EVENT with OCE RSSI based association rejection attribute is received.
3637      */
3638     @Test
testOceRssiBasedAssociationRejectionUpdatesRecentAssociationFailureStatus()3639     public void testOceRssiBasedAssociationRejectionUpdatesRecentAssociationFailureStatus()
3640             throws Exception {
3641         assumeTrue(SdkLevel.isAtLeastS());
3642         initializeAndAddNetworkAndVerifySuccess();
3643         AssociationRejectionData assocRejectData = new AssociationRejectionData();
3644         assocRejectData.ssid = NativeUtil.decodeSsid(TEST_SSID);
3645         assocRejectData.bssid = NativeUtil.macAddressToByteArray(TEST_BSSID_STR);
3646         assocRejectData.statusCode =
3647                 ISupplicantStaIfaceCallback.StatusCode.DENIED_POOR_CHANNEL_CONDITIONS;
3648         assocRejectData.isOceRssiBasedAssocRejectAttrPresent = true;
3649         assocRejectData.oceRssiBasedAssocRejectData.retryDelayS = 10;
3650         assocRejectData.oceRssiBasedAssocRejectData.deltaRssi = 20;
3651         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3652         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3653                 new AssocRejectEventInfo(assocRejectData));
3654         mLooper.dispatchAll();
3655         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3656                 eq(WifiConfiguration.RECENT_FAILURE_OCE_RSSI_BASED_ASSOCIATION_REJECTION));
3657     }
3658 
3659     /**
3660      * Verify that the recent failure association status is updated properly when
3661      * ASSOCIATION_REJECTION_EVENT with MBO association disallowed attribute is received.
3662      */
3663     @Test
testMboAssocDisallowedIndInAssocRejectUpdatesRecentAssociationFailureStatus()3664     public void testMboAssocDisallowedIndInAssocRejectUpdatesRecentAssociationFailureStatus()
3665             throws Exception {
3666         assumeTrue(SdkLevel.isAtLeastS());
3667         initializeAndAddNetworkAndVerifySuccess();
3668         AssociationRejectionData assocRejectData = new AssociationRejectionData();
3669         assocRejectData.ssid = NativeUtil.decodeSsid(TEST_SSID);
3670         assocRejectData.bssid = NativeUtil.macAddressToByteArray(TEST_BSSID_STR);
3671         assocRejectData.statusCode =
3672                 ISupplicantStaIfaceCallback.StatusCode.DENIED_POOR_CHANNEL_CONDITIONS;
3673         assocRejectData.isMboAssocDisallowedReasonCodePresent = true;
3674         assocRejectData.mboAssocDisallowedReason = MboAssocDisallowedReasonCode
3675                 .MAX_NUM_STA_ASSOCIATED;
3676         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3677         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3678                 new AssocRejectEventInfo(assocRejectData));
3679         mLooper.dispatchAll();
3680         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
3681                 eq(WifiConfiguration.RECENT_FAILURE_MBO_ASSOC_DISALLOWED_MAX_NUM_STA_ASSOCIATED));
3682     }
3683 
3684     /**
3685      * Verifies that the WifiBlocklistMonitor is notified, but the WifiLastResortWatchdog is
3686      * not notified of association rejections of type REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA.
3687      * @throws Exception
3688      */
3689     @Test
testAssociationRejectionWithReasonApUnableToHandleNewStaUpdatesWatchdog()3690     public void testAssociationRejectionWithReasonApUnableToHandleNewStaUpdatesWatchdog()
3691             throws Exception {
3692         initializeAndAddNetworkAndVerifySuccess();
3693         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3694         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3695                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR,
3696                         ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, false));
3697         mLooper.dispatchAll();
3698         verify(mWifiLastResortWatchdog, never()).noteConnectionFailureAndTriggerIfNeeded(
3699                 anyString(), anyString(), anyInt(), anyBoolean());
3700         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3701                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA),
3702                 anyInt());
3703     }
3704 
3705     /**
3706      * Verifies that the WifiBlocklistMonitor is notified, but the WifiLastResortWatchdog is
3707      * not notified of association rejections of type DENIED_INSUFFICIENT_BANDWIDTH.
3708      * @throws Exception
3709      */
3710     @Test
testAssociationRejectionWithReasonDeniedInsufficientBandwidth()3711     public void testAssociationRejectionWithReasonDeniedInsufficientBandwidth()
3712             throws Exception {
3713         initializeAndAddNetworkAndVerifySuccess();
3714         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3715         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3716                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR, ISupplicantStaIfaceCallback
3717                         .StatusCode.DENIED_INSUFFICIENT_BANDWIDTH, false));
3718         mLooper.dispatchAll();
3719         verify(mWifiLastResortWatchdog, never()).noteConnectionFailureAndTriggerIfNeeded(
3720                 anyString(), anyString(), anyInt(), anyBoolean());
3721         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3722                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA),
3723                 anyInt());
3724     }
3725 
3726     /**
3727      * Verifies that WifiLastResortWatchdog and WifiBlocklistMonitor is notified of
3728      * general association rejection failures.
3729      * @throws Exception
3730      */
3731     @Test
testAssociationRejectionUpdatesWatchdog()3732     public void testAssociationRejectionUpdatesWatchdog() throws Exception {
3733         initializeAndAddNetworkAndVerifySuccess();
3734         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID);
3735         config.carrierId = CARRIER_ID_1;
3736         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3737         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
3738                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false));
3739         mLooper.dispatchAll();
3740         verify(mWifiLastResortWatchdog).noteConnectionFailureAndTriggerIfNeeded(
3741                 anyString(), anyString(), anyInt(), anyBoolean());
3742         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3743                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION), anyInt());
3744         verify(mWifiMetrics).incrementNumOfCarrierWifiConnectionNonAuthFailure();
3745     }
3746 
3747     /**
3748      * Verifies that WifiLastResortWatchdog is not notified of authentication failures of type
3749      * ERROR_AUTH_FAILURE_WRONG_PSWD.
3750      * @throws Exception
3751      */
3752     @Test
testFailureWrongPassIsIgnoredByWatchdog()3753     public void testFailureWrongPassIsIgnoredByWatchdog() throws Exception {
3754         // Setup CONNECT_MODE & a WifiConfiguration
3755         initializeAndAddNetworkAndVerifySuccess();
3756         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3757         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
3758                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
3759                         SupplicantState.COMPLETED));
3760         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3761                 WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
3762         mLooper.dispatchAll();
3763         verify(mWifiLastResortWatchdog, never()).noteConnectionFailureAndTriggerIfNeeded(
3764                 anyString(), anyString(), anyInt(), anyBoolean());
3765         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3766                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_WRONG_PASSWORD), anyInt());
3767     }
3768 
3769     /**
3770      * Verifies that WifiLastResortWatchdog is not notified of authentication failures of type
3771      * ERROR_AUTH_FAILURE_EAP_FAILURE.
3772      * @throws Exception
3773      */
3774     @Test
testEapFailureIsIgnoredByWatchdog()3775     public void testEapFailureIsIgnoredByWatchdog() throws Exception {
3776         // Setup CONNECT_MODE & a WifiConfiguration
3777         initializeAndAddNetworkAndVerifySuccess();
3778         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3779         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
3780                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
3781                         SupplicantState.COMPLETED));
3782         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3783                 WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE);
3784         mLooper.dispatchAll();
3785         verify(mWifiLastResortWatchdog, never()).noteConnectionFailureAndTriggerIfNeeded(
3786                 anyString(), anyString(), anyInt(), anyBoolean());
3787         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3788                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_EAP_FAILURE), anyInt());
3789     }
3790 
3791     /**
3792      * Verifies that WifiLastResortWatchdog is notified of other types of authentication failures.
3793      * @throws Exception
3794      */
3795     @Test
testAuthenticationFailureUpdatesWatchdog()3796     public void testAuthenticationFailureUpdatesWatchdog() throws Exception {
3797         // Setup CONNECT_MODE & a WifiConfiguration
3798         initializeAndAddNetworkAndVerifySuccess();
3799         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3800         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
3801                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
3802                         SupplicantState.COMPLETED));
3803         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
3804                 WifiManager.ERROR_AUTH_FAILURE_TIMEOUT);
3805         mLooper.dispatchAll();
3806         verify(mWifiLastResortWatchdog).noteConnectionFailureAndTriggerIfNeeded(
3807                 anyString(), anyString(), anyInt(), anyBoolean());
3808         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(eq(TEST_BSSID_STR),
3809                 eq(TEST_SSID), eq(WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE), anyInt());
3810     }
3811 
3812     /**
3813      * Verify that WifiBlocklistMonitor is notified of the SSID pre-connection so that it could
3814      * send down to firmware the list of blocked BSSIDs.
3815      */
3816     @Test
testBssidBlocklistSentToFirmwareAfterCmdStartConnect()3817     public void testBssidBlocklistSentToFirmwareAfterCmdStartConnect() throws Exception {
3818         initializeAndAddNetworkAndVerifySuccess();
3819         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3820         verify(mWifiBlocklistMonitor, never()).updateFirmwareRoamingConfiguration(
3821                 Set.of(TEST_SSID));
3822         mLooper.dispatchAll();
3823         verify(mWifiBlocklistMonitor).updateFirmwareRoamingConfiguration(Set.of(TEST_SSID));
3824         // But don't expect to see connection success yet
3825         verify(mWifiScoreCard, never()).noteIpConfiguration(any());
3826         // And certainly not validation success
3827         verify(mWifiScoreCard, never()).noteValidationSuccess(any());
3828     }
3829 
3830     /**
3831      * Verifies that dhcp failures make WifiDiagnostics report CONNECTION_EVENT_FAILED and then
3832      * cancel any pending timeouts.
3833      * Also, send connection status to {@link WifiNetworkFactory} & {@link WifiConnectivityManager}.
3834      * @throws Exception
3835      */
3836     @Test
testReportConnectionEventIsCalledAfterDhcpFailure()3837     public void testReportConnectionEventIsCalledAfterDhcpFailure() throws Exception {
3838         mConnectedNetwork.getNetworkSelectionStatus()
3839                 .setCandidate(getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq)
3840                         .getScanResult());
3841         testDhcpFailure();
3842         verify(mWifiDiagnostics, atLeastOnce()).reportConnectionEvent(
3843                 eq(WifiDiagnostics.CONNECTION_EVENT_FAILED), any());
3844         verify(mWifiConnectivityManager, atLeastOnce()).handleConnectionAttemptEnded(
3845                 mClientModeManager,
3846                 WifiMetrics.ConnectionEvent.FAILURE_DHCP, TEST_BSSID_STR, TEST_SSID);
3847         verify(mWifiNetworkFactory, atLeastOnce()).handleConnectionAttemptEnded(
3848                 eq(WifiMetrics.ConnectionEvent.FAILURE_DHCP), any(WifiConfiguration.class),
3849                 eq(TEST_BSSID_STR));
3850         verify(mWifiNetworkSuggestionsManager, atLeastOnce()).handleConnectionAttemptEnded(
3851                 eq(WifiMetrics.ConnectionEvent.FAILURE_DHCP), any(WifiConfiguration.class),
3852                 any(String.class));
3853         verify(mWifiMetrics, never())
3854                 .incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3855         verifyConnectionEventTimeoutDoesNotOccur();
3856     }
3857 
3858     /**
3859      * Verifies that a successful validation make WifiDiagnostics report CONNECTION_EVENT_SUCCEEDED
3860      * and then cancel any pending timeouts.
3861      * Also, send connection status to {@link WifiNetworkFactory} & {@link WifiConnectivityManager}.
3862      */
3863     @Test
testReportConnectionEventIsCalledAfterSuccessfulConnection()3864     public void testReportConnectionEventIsCalledAfterSuccessfulConnection() throws Exception {
3865         mConnectedNetwork.getNetworkSelectionStatus()
3866                 .setCandidate(getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR1, sFreq)
3867                         .getScanResult());
3868         connect();
3869         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
3870                 mWifiNetworkAgentCallbackCaptor.capture());
3871         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
3872                 NetworkAgent.VALIDATION_STATUS_VALID, null /* captivePortalUrl */);
3873         mLooper.dispatchAll();
3874 
3875         verify(mWifiDiagnostics).reportConnectionEvent(
3876                 eq(WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED), any());
3877         verify(mWifiConnectivityManager).handleConnectionAttemptEnded(
3878                 mClientModeManager,
3879                 WifiMetrics.ConnectionEvent.FAILURE_NONE, TEST_BSSID_STR, TEST_SSID);
3880         verify(mWifiNetworkFactory).handleConnectionAttemptEnded(
3881                 eq(WifiMetrics.ConnectionEvent.FAILURE_NONE), any(WifiConfiguration.class),
3882                 eq(TEST_BSSID_STR));
3883         verify(mWifiNetworkSuggestionsManager).handleConnectionAttemptEnded(
3884                 eq(WifiMetrics.ConnectionEvent.FAILURE_NONE), any(WifiConfiguration.class),
3885                 any(String.class));
3886         verify(mCmiMonitor).onInternetValidated(mClientModeManager);
3887         // BSSID different, record this connection.
3888         verify(mWifiMetrics).incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3889         verifyConnectionEventTimeoutDoesNotOccur();
3890     }
3891 
3892     /**
3893      * Verify that score card is notified of a connection attempt
3894      */
3895     @Test
testScoreCardNoteConnectionAttemptAfterCmdStartConnect()3896     public void testScoreCardNoteConnectionAttemptAfterCmdStartConnect() throws Exception {
3897         initializeAndAddNetworkAndVerifySuccess();
3898         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
3899         verify(mWifiScoreCard, never()).noteConnectionAttempt(any(), anyInt(), anyString());
3900         mLooper.dispatchAll();
3901         verify(mWifiScoreCard).noteConnectionAttempt(any(), anyInt(), anyString());
3902         verify(mWifiConfigManager).findScanRssi(anyInt(), anyInt());
3903         // But don't expect to see connection success yet
3904         verify(mWifiScoreCard, never()).noteIpConfiguration(any());
3905         // And certainly not validation success
3906         verify(mWifiScoreCard, never()).noteValidationSuccess(any());
3907 
3908     }
3909 
3910     /**
3911      * Verify that score card is notified of a successful connection
3912      */
3913     @Test
testScoreCardNoteConnectionComplete()3914     public void testScoreCardNoteConnectionComplete() throws Exception {
3915         Pair<String, String> l2KeyAndCluster = Pair.create("Wad", "Gab");
3916         when(mWifiScoreCard.getL2KeyAndGroupHint(any())).thenReturn(l2KeyAndCluster);
3917         connect();
3918         mLooper.dispatchAll();
3919         verify(mWifiScoreCard).noteIpConfiguration(any());
3920         ArgumentCaptor<Layer2InformationParcelable> captor =
3921                 ArgumentCaptor.forClass(Layer2InformationParcelable.class);
3922         verify(mIpClient, atLeastOnce()).updateLayer2Information(captor.capture());
3923         final Layer2InformationParcelable info = captor.getValue();
3924         assertEquals(info.l2Key, "Wad");
3925         assertEquals(info.cluster, "Gab");
3926     }
3927 
3928     /**
3929      * Verify that score card/health monitor are notified when wifi is disabled while disconnected
3930      */
3931     @Test
testScoreCardNoteWifiDisabledWhileDisconnected()3932     public void testScoreCardNoteWifiDisabledWhileDisconnected() throws Exception {
3933         // connecting and disconnecting shouldn't note wifi disabled
3934         disconnect();
3935         mLooper.dispatchAll();
3936 
3937         verify(mWifiScoreCard, times(1)).resetConnectionState(WIFI_IFACE_NAME);
3938         verify(mWifiScoreCard, never()).noteWifiDisabled(any());
3939 
3940         // disabling while disconnected should note wifi disabled
3941         mCmi.stop();
3942         mLooper.dispatchAll();
3943         verify(mWifiScoreCard, times(2)).resetConnectionState(WIFI_IFACE_NAME);
3944     }
3945 
3946     /**
3947      * Verify that score card/health monitor are notified when wifi is disabled while connected
3948      */
3949     @Test
testScoreCardNoteWifiDisabledWhileConnected()3950     public void testScoreCardNoteWifiDisabledWhileConnected() throws Exception {
3951         // Get into connected state
3952         connect();
3953         mLooper.dispatchAll();
3954         verify(mWifiScoreCard, never()).noteWifiDisabled(any());
3955 
3956         // disabling while connected should note wifi disabled
3957         mCmi.stop();
3958         mLooper.dispatchAll();
3959 
3960         verify(mWifiScoreCard).noteWifiDisabled(any());
3961         verify(mWifiScoreCard).resetConnectionState(WIFI_IFACE_NAME);
3962     }
3963 
3964     /**
3965      * Verify that IPClient instance is shutdown when wifi is disabled.
3966      */
3967     @Test
verifyIpClientShutdownWhenDisabled()3968     public void verifyIpClientShutdownWhenDisabled() throws Exception {
3969         mCmi.stop();
3970         mLooper.dispatchAll();
3971         verify(mIpClient).shutdown();
3972     }
3973 
3974     /**
3975      * Verify that WifiInfo's MAC address is updated when the state machine receives
3976      * NETWORK_CONNECTION_EVENT while in L3ConnectedState.
3977      */
3978     @Test
verifyWifiInfoMacUpdatedWithNetworkConnectionWhileConnected()3979     public void verifyWifiInfoMacUpdatedWithNetworkConnectionWhileConnected() throws Exception {
3980         connect();
3981         assertEquals("L3ConnectedState", getCurrentState().getName());
3982         assertEquals(TEST_LOCAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3983 
3984         // Verify receiving a NETWORK_CONNECTION_EVENT changes the MAC in WifiInfo
3985         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
3986                 .thenReturn(TEST_GLOBAL_MAC_ADDRESS.toString());
3987         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
3988                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
3989         mLooper.dispatchAll();
3990         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
3991     }
3992 
3993     /**
3994      * Verify that WifiInfo's MAC address is updated when the state machine receives
3995      * NETWORK_CONNECTION_EVENT while in DisconnectedState.
3996      */
3997     @Test
verifyWifiInfoMacUpdatedWithNetworkConnectionWhileDisconnected()3998     public void verifyWifiInfoMacUpdatedWithNetworkConnectionWhileDisconnected() throws Exception {
3999         disconnect();
4000         assertEquals("DisconnectedState", getCurrentState().getName());
4001         // Since MAC randomization is enabled, wifiInfo's MAC should be set to default MAC
4002         // when disconnect happens.
4003         assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mWifiInfo.getMacAddress());
4004 
4005         setupAndStartConnectSequence(mConnectedNetwork);
4006         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
4007                 .thenReturn(TEST_LOCAL_MAC_ADDRESS.toString());
4008         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
4009                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
4010         mLooper.dispatchAll();
4011         assertEquals(TEST_LOCAL_MAC_ADDRESS.toString(), mWifiInfo.getMacAddress());
4012     }
4013 
4014     @Test
internetValidationFailure_notUserSelected_expectTemporarilyDisabled()4015     public void internetValidationFailure_notUserSelected_expectTemporarilyDisabled()
4016             throws Exception {
4017         // Setup RSSI poll to update WifiInfo with low RSSI
4018         mCmi.enableRssiPolling(true);
4019         WifiLinkLayerStats llStats = new WifiLinkLayerStats();
4020         llStats.txmpdu_be = 1000;
4021         llStats.rxmpdu_bk = 2000;
4022         WifiNl80211Manager.SignalPollResult signalPollResult =
4023                 new WifiNl80211Manager.SignalPollResult(RSSI_THRESHOLD_BREACH_MIN, 65, 54, sFreq);
4024         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(llStats);
4025         when(mWifiNative.signalPoll(any())).thenReturn(signalPollResult);
4026 
4027         connect();
4028         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4029                 mWifiNetworkAgentCallbackCaptor.capture());
4030 
4031         WifiConfiguration currentNetwork = new WifiConfiguration();
4032         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
4033         currentNetwork.SSID = DEFAULT_TEST_SSID;
4034         currentNetwork.noInternetAccessExpected = false;
4035         currentNetwork.numNoInternetAccessReports = 1;
4036 
4037         // not user selected
4038         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID))
4039                 .thenReturn(currentNetwork);
4040         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID + 1);
4041 
4042         // internet validation failure
4043         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4044                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, null /* captivePortalUr; */);
4045         mLooper.dispatchAll();
4046 
4047         verify(mWifiConfigManager)
4048                 .incrementNetworkNoInternetAccessReports(FRAMEWORK_NETWORK_ID);
4049         // expect temporarily disabled
4050         verify(mWifiConfigManager).updateNetworkSelectionStatus(
4051                 FRAMEWORK_NETWORK_ID, DISABLED_NO_INTERNET_TEMPORARY);
4052         verify(mWifiBlocklistMonitor).handleBssidConnectionFailure(TEST_BSSID_STR, TEST_SSID,
4053                 WifiBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE, RSSI_THRESHOLD_BREACH_MIN);
4054         verify(mWifiScoreCard).noteValidationFailure(any());
4055     }
4056 
4057     @Test
mbb_internetValidationError_expectDisconnect()4058     public void mbb_internetValidationError_expectDisconnect() throws Exception {
4059         connect();
4060         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4061                 mWifiNetworkAgentCallbackCaptor.capture());
4062 
4063         // Make Before Break CMM
4064         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
4065 
4066         // internet validation failure
4067         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4068                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, null /* captivePortalUr; */);
4069         mLooper.dispatchAll();
4070 
4071         // expect disconnection
4072         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
4073     }
4074 
4075     @Test
captivePortalDetected_notifiesCmiMonitor()4076     public void captivePortalDetected_notifiesCmiMonitor() throws Exception {
4077         connect();
4078         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4079                 mWifiNetworkAgentCallbackCaptor.capture());
4080 
4081         // captive portal detected
4082         when(mMockUri.toString()).thenReturn("TEST_URI");
4083         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4084                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, mMockUri);
4085         mLooper.dispatchAll();
4086 
4087         verify(mWifiConfigManager).noteCaptivePortalDetected(anyInt());
4088         verify(mCmiMonitor).onCaptivePortalDetected(mClientModeManager);
4089     }
4090 
4091     @Test
internetValidationFailure_userSelectedRecently_expectNotDisabled()4092     public void internetValidationFailure_userSelectedRecently_expectNotDisabled()
4093             throws Exception {
4094         connect();
4095         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4096                 mWifiNetworkAgentCallbackCaptor.capture());
4097 
4098         WifiConfiguration currentNetwork = new WifiConfiguration();
4099         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
4100         currentNetwork.noInternetAccessExpected = false;
4101         currentNetwork.numNoInternetAccessReports = 1;
4102 
4103         // user last picked this network
4104         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID))
4105                 .thenReturn(currentNetwork);
4106         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID);
4107 
4108         // user recently picked this network
4109         when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(1234L);
4110         when(mClock.getElapsedSinceBootMillis()).thenReturn(1235L);
4111 
4112         // internet validation failure
4113         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4114                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, null /* captivePortalUrl */);
4115         mLooper.dispatchAll();
4116 
4117         verify(mWifiConfigManager)
4118                 .incrementNetworkNoInternetAccessReports(FRAMEWORK_NETWORK_ID);
4119         // expect not disabled
4120         verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(
4121                 FRAMEWORK_NETWORK_ID, DISABLED_NO_INTERNET_TEMPORARY);
4122     }
4123 
4124     @Test
internetValidationFailure_userSelectedTooLongAgo_expectTemporarilyDisabled()4125     public void internetValidationFailure_userSelectedTooLongAgo_expectTemporarilyDisabled()
4126             throws Exception {
4127         connect();
4128         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4129                 mWifiNetworkAgentCallbackCaptor.capture());
4130 
4131         WifiConfiguration currentNetwork = new WifiConfiguration();
4132         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
4133         currentNetwork.noInternetAccessExpected = false;
4134         currentNetwork.numNoInternetAccessReports = 1;
4135 
4136         // user last picked this network
4137         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID))
4138                 .thenReturn(currentNetwork);
4139         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID);
4140 
4141         // user picked this network a long time ago
4142         when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(1234L);
4143         when(mClock.getElapsedSinceBootMillis())
4144                 .thenReturn(1235L + ClientModeImpl.LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS);
4145 
4146         // internet validation failure
4147         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4148                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, null /* captivePortalUrl */);
4149         mLooper.dispatchAll();
4150 
4151         verify(mWifiConfigManager)
4152                 .incrementNetworkNoInternetAccessReports(FRAMEWORK_NETWORK_ID);
4153         // expect temporarily disabled
4154         verify(mWifiConfigManager).updateNetworkSelectionStatus(
4155                 FRAMEWORK_NETWORK_ID, DISABLED_NO_INTERNET_TEMPORARY);
4156     }
4157 
4158     @Test
noInternetExpectedNetwork_internetValidationFailure_notUserSelected_expectNotDisabled()4159     public void noInternetExpectedNetwork_internetValidationFailure_notUserSelected_expectNotDisabled()
4160             throws Exception {
4161         connect();
4162         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4163                 mWifiNetworkAgentCallbackCaptor.capture());
4164 
4165         WifiConfiguration currentNetwork = new WifiConfiguration();
4166         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
4167         // no internet expected
4168         currentNetwork.noInternetAccessExpected = true;
4169         currentNetwork.numNoInternetAccessReports = 1;
4170 
4171         // user didn't pick this network
4172         when(mWifiConfigManager.getConfiguredNetwork(FRAMEWORK_NETWORK_ID))
4173                 .thenReturn(currentNetwork);
4174         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID + 1);
4175 
4176         // internet validation failure
4177         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4178                 NetworkAgent.VALIDATION_STATUS_NOT_VALID, null /* captivePortalUrl */);
4179         mLooper.dispatchAll();
4180 
4181         verify(mWifiConfigManager)
4182                 .incrementNetworkNoInternetAccessReports(FRAMEWORK_NETWORK_ID);
4183         // expect not disabled
4184         verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(
4185                 FRAMEWORK_NETWORK_ID, DISABLED_NO_INTERNET_TEMPORARY);
4186     }
4187 
4188     /**
4189      * Verify that we do not set the user connect choice after a successful connection if the
4190      * connection is not made by the user.
4191      */
4192     @Test
testNonSettingsConnectionNotSetUserConnectChoice()4193     public void testNonSettingsConnectionNotSetUserConnectChoice() throws Exception {
4194         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
4195         connect();
4196         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
4197         verify(mWifiConfigManager).updateNetworkAfterConnect(eq(FRAMEWORK_NETWORK_ID), eq(false),
4198                 anyInt());
4199     }
4200 
4201     /**
4202      * Verify that we do not set the user connect choice after connecting to a newly added network.
4203      */
4204     @Test
testNoSetUserConnectChoiceOnFirstConnection()4205     public void testNoSetUserConnectChoiceOnFirstConnection() throws Exception {
4206         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
4207         connect();
4208         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
4209         verify(mWifiConfigManager).updateNetworkAfterConnect(eq(FRAMEWORK_NETWORK_ID), eq(false),
4210                 anyInt());
4211     }
4212 
4213     /**
4214      * Verify that on the second successful connection to a network we set the user connect choice.
4215      */
4216     @Test
testConnectionSetUserConnectChoiceOnSecondConnection()4217     public void testConnectionSetUserConnectChoiceOnSecondConnection() throws Exception {
4218         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
4219         mTestNetworkParams.hasEverConnected = true;
4220         connect();
4221         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
4222         verify(mWifiConfigManager).updateNetworkAfterConnect(eq(FRAMEWORK_NETWORK_ID), eq(true),
4223                 anyInt());
4224     }
4225 
4226     /**
4227      * Verify that we enable the network when we detect validated internet access.
4228      */
4229     @Test
verifyNetworkSelectionEnableOnInternetValidation()4230     public void verifyNetworkSelectionEnableOnInternetValidation() throws Exception {
4231         // Simulate the first connection.
4232         connect();
4233         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
4234         verify(mWifiBlocklistMonitor).handleDhcpProvisioningSuccess(TEST_BSSID_STR, TEST_SSID);
4235         verify(mWifiBlocklistMonitor, never()).handleNetworkValidationSuccess(
4236                 TEST_BSSID_STR, TEST_SSID);
4237 
4238         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4239                 mWifiNetworkAgentCallbackCaptor.capture());
4240 
4241         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID + 1);
4242 
4243         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4244                 NetworkAgent.VALIDATION_STATUS_VALID, null /* captivePortalUrl */);
4245         mLooper.dispatchAll();
4246 
4247         verify(mWifiConfigManager)
4248                 .setNetworkValidatedInternetAccess(FRAMEWORK_NETWORK_ID, true);
4249         verify(mWifiConfigManager).updateNetworkSelectionStatus(
4250                 FRAMEWORK_NETWORK_ID, DISABLED_NONE);
4251         verify(mWifiScoreCard).noteValidationSuccess(any());
4252         verify(mWifiBlocklistMonitor).handleNetworkValidationSuccess(TEST_BSSID_STR, TEST_SSID);
4253     }
4254 
4255     /**
4256      * Verify that the logic clears the terms and conditions URL after we got a notification that
4257      * the network was validated (i.e. the user accepted and internt access is available).
4258      */
4259     @Test
testTermsAndConditionsClearUrlAfterNetworkValidation()4260     public void testTermsAndConditionsClearUrlAfterNetworkValidation() throws Exception {
4261         assumeTrue(SdkLevel.isAtLeastS());
4262         InOrder inOrder = inOrder(mWifiNetworkAgent);
4263 
4264         // Simulate the first connection.
4265         mConnectedNetwork = spy(WifiConfigurationTestUtil.createPasspointNetwork());
4266         WnmData wnmData = WnmData.createTermsAndConditionsAccetanceRequiredEvent(TEST_BSSID,
4267                 TEST_TERMS_AND_CONDITIONS_URL);
4268         when(mPasspointManager.handleTermsAndConditionsEvent(eq(wnmData),
4269                 any(WifiConfiguration.class))).thenReturn(new URL(TEST_TERMS_AND_CONDITIONS_URL));
4270         connect(wnmData);
4271         // Verify that link properties contains the T&C URL and captive is set to true
4272         inOrder.verify(mWifiNetworkAgent)
4273                 .sendLinkProperties(argThat(linkProperties -> TEST_TERMS_AND_CONDITIONS_URL.equals(
4274                         linkProperties.getCaptivePortalData().getUserPortalUrl().toString())
4275                         && linkProperties.getCaptivePortalData().isCaptive()));
4276         verify(mWifiBlocklistMonitor).handleBssidConnectionSuccess(TEST_BSSID_STR, TEST_SSID);
4277         verify(mWifiBlocklistMonitor).handleDhcpProvisioningSuccess(TEST_BSSID_STR, TEST_SSID);
4278         verify(mWifiBlocklistMonitor, never())
4279                 .handleNetworkValidationSuccess(TEST_BSSID_STR, TEST_SSID);
4280         verify(mWifiInjector).makeWifiNetworkAgent(any(), any(), any(), any(),
4281                 mWifiNetworkAgentCallbackCaptor.capture());
4282 
4283         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID + 1);
4284         mWifiNetworkAgentCallbackCaptor.getValue().onValidationStatus(
4285                 NetworkAgent.VALIDATION_STATUS_VALID, null /* captivePortalUrl */);
4286         mLooper.dispatchAll();
4287 
4288         verify(mWifiConfigManager)
4289                 .setNetworkValidatedInternetAccess(FRAMEWORK_NETWORK_ID, true);
4290         verify(mWifiConfigManager).updateNetworkSelectionStatus(
4291                 FRAMEWORK_NETWORK_ID, DISABLED_NONE);
4292         verify(mWifiScoreCard).noteValidationSuccess(any());
4293         verify(mWifiBlocklistMonitor).handleNetworkValidationSuccess(TEST_BSSID_STR, TEST_SSID);
4294 
4295         // Now that the network has been validated, link properties must not have a T&C URL anymore
4296         // and captive is set to false
4297         inOrder.verify(mWifiNetworkAgent)
4298                 .sendLinkProperties(argThat(linkProperties ->
4299                         linkProperties.getCaptivePortalData().getUserPortalUrl() == null
4300                                 && !linkProperties.getCaptivePortalData().isCaptive()));
4301     }
4302 
connectWithValidInitRssi(int initRssiDbm)4303     private void connectWithValidInitRssi(int initRssiDbm) throws Exception {
4304         triggerConnect();
4305         mWifiInfo.setRssi(initRssiDbm);
4306         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
4307                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
4308                         SupplicantState.ASSOCIATED));
4309         mLooper.dispatchAll();
4310 
4311         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
4312                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
4313         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
4314                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
4315         mLooper.dispatchAll();
4316 
4317         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
4318                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
4319                         SupplicantState.COMPLETED));
4320         mLooper.dispatchAll();
4321 
4322         assertEquals("L3ProvisioningState", getCurrentState().getName());
4323 
4324         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
4325         dhcpResults.baseConfiguration = new StaticIpConfiguration();
4326         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
4327         dhcpResults.baseConfiguration.ipAddress =
4328                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
4329         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
4330         dhcpResults.leaseDuration = 3600;
4331 
4332         injectDhcpSuccess(dhcpResults);
4333         mLooper.dispatchAll();
4334 
4335     }
4336 
4337     /**
4338      * Verify that we set the INTERNET and bandwidth capability in the network agent when connected
4339      * as a result of auto-join/legacy API's. Also verify up/down stream bandwidth values when
4340      * Rx link speed is unavailable.
4341      */
4342     @Test
verifyNetworkCapabilities()4343     public void verifyNetworkCapabilities() throws Exception {
4344         mWifiInfo.setFrequency(5825);
4345         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(40_000);
4346         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(50_000);
4347         when(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName(any(), any()))
4348                 .thenReturn(Pair.create(Process.INVALID_UID, ""));
4349         // Simulate the first connection.
4350         connectWithValidInitRssi(-42);
4351 
4352         ArgumentCaptor<NetworkCapabilities> networkCapabilitiesCaptor =
4353                 ArgumentCaptor.forClass(NetworkCapabilities.class);
4354         verify(mWifiInjector).makeWifiNetworkAgent(
4355                 networkCapabilitiesCaptor.capture(), any(), any(), any(), any());
4356 
4357         NetworkCapabilities networkCapabilities = networkCapabilitiesCaptor.getValue();
4358         assertNotNull(networkCapabilities);
4359 
4360         // Should have internet capability.
4361         assertTrue(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
4362 
4363         assertEquals(mConnectedNetwork.creatorUid, networkCapabilities.getOwnerUid());
4364         assertArrayEquals(
4365                 new int[] {mConnectedNetwork.creatorUid},
4366                 networkCapabilities.getAdministratorUids());
4367 
4368         // Should set bandwidth correctly
4369         assertEquals(-42, mWifiInfo.getRssi());
4370         assertEquals(40_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
4371         assertEquals(50_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
4372 
4373         // Should set band correctly.
4374         // There is no accessor to get the band from the WifiNetworkAgentSpecifier, so match against
4375         // a WifiNetworkSpecifier.
4376         // TODO: should there be?
4377         final NetworkSpecifier spec = networkCapabilities.getNetworkSpecifier();
4378         assertTrue(spec instanceof WifiNetworkAgentSpecifier);
4379         final WifiNetworkAgentSpecifier wnas = (WifiNetworkAgentSpecifier) spec;
4380         assertTrue(wnas.satisfiesNetworkSpecifier(
4381                 new WifiNetworkSpecifier.Builder().setBand(ScanResult.WIFI_BAND_5_GHZ).build()));
4382     }
4383 
4384     /**
4385      * Verify that we don't set the INTERNET capability in the network agent when connected
4386      * as a result of the new network request API. Also verify up/down stream bandwidth values
4387      * when both Tx and Rx link speed are unavailable.
4388      */
4389     @Test
verifyNetworkCapabilitiesForSpecificRequest()4390     public void verifyNetworkCapabilitiesForSpecificRequest() throws Exception {
4391         mWifiInfo.setFrequency(2437);
4392         when(mPerNetwork.getTxLinkBandwidthKbps()).thenReturn(30_000);
4393         when(mPerNetwork.getRxLinkBandwidthKbps()).thenReturn(40_000);
4394         when(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName(any(), any()))
4395                 .thenReturn(Pair.create(TEST_UID, OP_PACKAGE_NAME));
4396         // Simulate the first connection.
4397         connectWithValidInitRssi(-42);
4398         ArgumentCaptor<NetworkCapabilities> networkCapabilitiesCaptor =
4399                 ArgumentCaptor.forClass(NetworkCapabilities.class);
4400 
4401         verify(mWifiInjector).makeWifiNetworkAgent(
4402                 networkCapabilitiesCaptor.capture(), any(), any(), any(), any());
4403 
4404         NetworkCapabilities networkCapabilities = networkCapabilitiesCaptor.getValue();
4405         assertNotNull(networkCapabilities);
4406 
4407         // should not have internet capability.
4408         assertFalse(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
4409 
4410         NetworkSpecifier networkSpecifier = networkCapabilities.getNetworkSpecifier();
4411         assertTrue(networkSpecifier instanceof WifiNetworkAgentSpecifier);
4412         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
4413                 (WifiNetworkAgentSpecifier) networkSpecifier;
4414 
4415         // createNetworkAgentSpecifier does not write the BSSID to the current wifi configuration.
4416         WifiConfiguration expectedConfig = new WifiConfiguration(
4417                 mCmi.getConnectedWifiConfiguration());
4418         expectedConfig.BSSID = TEST_BSSID_STR;
4419         WifiNetworkAgentSpecifier expectedWifiNetworkAgentSpecifier =
4420                 new WifiNetworkAgentSpecifier(expectedConfig, ScanResult.WIFI_BAND_24_GHZ,
4421                         true /* matchLocalOnlySpecifiers */);
4422         assertEquals(expectedWifiNetworkAgentSpecifier, wifiNetworkAgentSpecifier);
4423         assertEquals(TEST_UID, networkCapabilities.getRequestorUid());
4424         assertEquals(OP_PACKAGE_NAME, networkCapabilities.getRequestorPackageName());
4425         assertEquals(30_000, networkCapabilities.getLinkUpstreamBandwidthKbps());
4426         assertEquals(40_000, networkCapabilities.getLinkDownstreamBandwidthKbps());
4427     }
4428 
4429     /**
4430      * Verify that we check for data stall during rssi poll
4431      * and then check that wifi link layer usage data are being updated.
4432      */
4433     @Test
verifyRssiPollChecksDataStall()4434     public void verifyRssiPollChecksDataStall() throws Exception {
4435         mCmi.enableRssiPolling(true);
4436         connect();
4437 
4438         WifiLinkLayerStats oldLLStats = new WifiLinkLayerStats();
4439         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(oldLLStats);
4440         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
4441         mLooper.dispatchAll();
4442         WifiLinkLayerStats newLLStats = new WifiLinkLayerStats();
4443         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(newLLStats);
4444         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
4445         mLooper.dispatchAll();
4446         verify(mWifiDataStall).checkDataStallAndThroughputSufficiency(WIFI_IFACE_NAME,
4447                 mConnectionCapabilities, oldLLStats, newLLStats, mWifiInfo);
4448         verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(WIFI_IFACE_NAME, newLLStats);
4449     }
4450 
4451     /**
4452      * Verify that we update wifi usability stats entries during rssi poll and that when we get
4453      * a data stall we label and save the current list of usability stats entries.
4454      * @throws Exception
4455      */
4456     @Test
verifyRssiPollUpdatesWifiUsabilityMetrics()4457     public void verifyRssiPollUpdatesWifiUsabilityMetrics() throws Exception {
4458         mCmi.enableRssiPolling(true);
4459         connect();
4460 
4461         WifiLinkLayerStats stats = new WifiLinkLayerStats();
4462         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(stats);
4463         when(mWifiDataStall.checkDataStallAndThroughputSufficiency(any(),
4464                 any(), any(), any(), any()))
4465                 .thenReturn(WifiIsUnusableEvent.TYPE_UNKNOWN);
4466         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
4467         mLooper.dispatchAll();
4468         verify(mWifiMetrics).updateWifiUsabilityStatsEntries(any(), any(), eq(stats));
4469         verify(mWifiMetrics, never()).addToWifiUsabilityStatsList(any(),
4470                 WifiUsabilityStats.LABEL_BAD, eq(anyInt()), eq(-1));
4471 
4472         when(mWifiDataStall.checkDataStallAndThroughputSufficiency(any(), any(), any(), any(),
4473                 any()))
4474                 .thenReturn(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
4475         when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
4476         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
4477         mLooper.dispatchAll();
4478         verify(mWifiMetrics, times(2)).updateWifiUsabilityStatsEntries(any(), any(), eq(stats));
4479         when(mClock.getElapsedSinceBootMillis())
4480                 .thenReturn(10L + ClientModeImpl.DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS);
4481         mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
4482         mLooper.dispatchAll();
4483         verify(mWifiMetrics).addToWifiUsabilityStatsList(WIFI_IFACE_NAME,
4484                 WifiUsabilityStats.LABEL_BAD, WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX, -1);
4485     }
4486 
4487     /**
4488      * Verify that when ordered to setPowerSave(true) while Interface is created,
4489      * WifiNative is called with the right powerSave mode.
4490      */
4491     @Test
verifySetPowerSaveTrueSuccess()4492     public void verifySetPowerSaveTrueSuccess() throws Exception {
4493         // called once during setup()
4494         verify(mWifiNative).setPowerSave(WIFI_IFACE_NAME, true);
4495 
4496         assertTrue(mCmi.setPowerSave(true));
4497         verify(mWifiNative, times(2)).setPowerSave(WIFI_IFACE_NAME, true);
4498     }
4499 
4500     /**
4501      * Verify that when ordered to setPowerSave(false) while Interface is created,
4502      * WifiNative is called with the right powerSave mode.
4503      */
4504     @Test
verifySetPowerSaveFalseSuccess()4505     public void verifySetPowerSaveFalseSuccess() throws Exception {
4506         assertTrue(mCmi.setPowerSave(false));
4507         verify(mWifiNative).setPowerSave(WIFI_IFACE_NAME, false);
4508     }
4509 
4510     /**
4511      * Verify that we call into WifiTrafficPoller during rssi poll
4512      */
4513     @Test
verifyRssiPollCallsWifiTrafficPoller()4514     public void verifyRssiPollCallsWifiTrafficPoller() throws Exception {
4515         mCmi.enableRssiPolling(true);
4516         connect();
4517 
4518         verify(mWifiTrafficPoller).notifyOnDataActivity(anyLong(), anyLong());
4519     }
4520 
4521     /**
4522      * Verify that LinkProbeManager is updated during RSSI poll
4523      */
4524     @Test
verifyRssiPollCallsLinkProbeManager()4525     public void verifyRssiPollCallsLinkProbeManager() throws Exception {
4526         mCmi.enableRssiPolling(true);
4527 
4528         connect();
4529         // reset() should be called when RSSI polling is enabled and entering L2L3ConnectedState
4530         verify(mLinkProbeManager).resetOnNewConnection(); // called first time here
4531         verify(mLinkProbeManager, never()).resetOnScreenTurnedOn(); // not called
4532         verify(mLinkProbeManager).updateConnectionStats(any(), any());
4533 
4534         mCmi.enableRssiPolling(false);
4535         mLooper.dispatchAll();
4536         // reset() should be called when in L2L3ConnectedState (or child states) and RSSI polling
4537         // becomes enabled
4538         mCmi.enableRssiPolling(true);
4539         mLooper.dispatchAll();
4540         verify(mLinkProbeManager, times(1)).resetOnNewConnection(); // verify not called again
4541         verify(mLinkProbeManager).resetOnScreenTurnedOn(); // verify called here
4542     }
4543 
4544     /**
4545      * Verify that when ordered to setLowLatencyMode(true),
4546      * WifiNative is called with the right lowLatency mode.
4547      */
4548     @Test
verifySetLowLatencyTrueSuccess()4549     public void verifySetLowLatencyTrueSuccess() throws Exception {
4550         when(mWifiNative.setLowLatencyMode(anyBoolean())).thenReturn(true);
4551         assertTrue(mCmi.setLowLatencyMode(true));
4552         verify(mWifiNative).setLowLatencyMode(true);
4553     }
4554 
4555     /**
4556      * Verify that when ordered to setLowLatencyMode(false),
4557      * WifiNative is called with the right lowLatency mode.
4558      */
4559     @Test
verifySetLowLatencyFalseSuccess()4560     public void verifySetLowLatencyFalseSuccess() throws Exception {
4561         when(mWifiNative.setLowLatencyMode(anyBoolean())).thenReturn(true);
4562         assertTrue(mCmi.setLowLatencyMode(false));
4563         verify(mWifiNative).setLowLatencyMode(false);
4564     }
4565 
4566     /**
4567      * Verify that when WifiNative fails to set low latency mode,
4568      * then the call setLowLatencyMode() returns with failure,
4569      */
4570     @Test
verifySetLowLatencyModeFailure()4571     public void verifySetLowLatencyModeFailure() throws Exception {
4572         final boolean lowLatencyMode = true;
4573         when(mWifiNative.setLowLatencyMode(anyBoolean())).thenReturn(false);
4574         assertFalse(mCmi.setLowLatencyMode(lowLatencyMode));
4575         verify(mWifiNative).setLowLatencyMode(eq(lowLatencyMode));
4576     }
4577 
4578     /**
4579      * Verify getting the factory MAC address success case.
4580      */
4581     @Test
testGetFactoryMacAddressSuccess()4582     public void testGetFactoryMacAddressSuccess() throws Exception {
4583         initializeAndAddNetworkAndVerifySuccess();
4584 
4585         clearInvocations(mWifiNative, mSettingsConfigStore);
4586 
4587         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mCmi.getFactoryMacAddress());
4588         verify(mSettingsConfigStore).get(WIFI_STA_FACTORY_MAC_ADDRESS); // try config store.
4589         verify(mWifiNative, never()).getStaFactoryMacAddress(WIFI_IFACE_NAME); // not native
4590         verify(mSettingsConfigStore, never()).put(eq(WIFI_STA_FACTORY_MAC_ADDRESS), any());
4591 
4592         clearInvocations(mWifiNative, mSettingsConfigStore);
4593 
4594         // get it again, should now use the config store MAC address, not native.
4595         assertEquals(TEST_GLOBAL_MAC_ADDRESS.toString(), mCmi.getFactoryMacAddress());
4596         verify(mSettingsConfigStore).get(WIFI_STA_FACTORY_MAC_ADDRESS);
4597 
4598         verifyNoMoreInteractions(mWifiNative, mSettingsConfigStore);
4599     }
4600 
4601     /**
4602      * Verify getting the factory MAC address failure case.
4603      */
4604     @Test
testGetFactoryMacAddressFail()4605     public void testGetFactoryMacAddressFail() throws Exception {
4606         initializeAndAddNetworkAndVerifySuccess();
4607 
4608         clearInvocations(mWifiNative, mSettingsConfigStore);
4609 
4610         when(mSettingsConfigStore.get(WIFI_STA_FACTORY_MAC_ADDRESS)).thenReturn(null);
4611         when(mWifiNative.getStaFactoryMacAddress(WIFI_IFACE_NAME)).thenReturn(null);
4612         assertNull(mCmi.getFactoryMacAddress());
4613         verify(mSettingsConfigStore).get(WIFI_STA_FACTORY_MAC_ADDRESS);
4614         verify(mWifiNative).getStaFactoryMacAddress(WIFI_IFACE_NAME);
4615 
4616         verifyNoMoreInteractions(mWifiNative, mSettingsConfigStore);
4617     }
4618 
4619     /**
4620      * Verify that when WifiNative#getStaFactoryMacAddress fails, if the device does not support
4621      * MAC randomization then the currently programmed MAC address gets returned.
4622      */
4623     @Test
testGetFactoryMacAddressFailWithNoMacRandomizationSupport()4624     public void testGetFactoryMacAddressFailWithNoMacRandomizationSupport() throws Exception {
4625         // reset mWifiNative since initializeCmi() was called in setup()
4626         resetWifiNative();
4627 
4628         when(mWifiGlobals.isConnectedMacRandomizationEnabled()).thenReturn(false);
4629         initializeCmi();
4630         initializeAndAddNetworkAndVerifySuccess();
4631 
4632         clearInvocations(mWifiNative, mSettingsConfigStore);
4633 
4634         when(mSettingsConfigStore.get(WIFI_STA_FACTORY_MAC_ADDRESS)).thenReturn(null);
4635         when(mWifiNative.getStaFactoryMacAddress(WIFI_IFACE_NAME)).thenReturn(null);
4636         when(mWifiNative.getMacAddress(WIFI_IFACE_NAME))
4637                 .thenReturn(TEST_DEFAULT_MAC_ADDRESS.toString());
4638         assertEquals(TEST_DEFAULT_MAC_ADDRESS.toString(), mCmi.getFactoryMacAddress());
4639 
4640         verify(mSettingsConfigStore).get(WIFI_STA_FACTORY_MAC_ADDRESS);
4641         verify(mWifiNative).getStaFactoryMacAddress(WIFI_IFACE_NAME);
4642         verify(mWifiNative).getMacAddress(WIFI_IFACE_NAME);
4643 
4644         verifyNoMoreInteractions(mWifiNative, mSettingsConfigStore);
4645     }
4646 
4647     /**
4648      * Verify the MAC address is being randomized at start to prevent leaking the factory MAC.
4649      */
4650     @Test
testRandomizeMacAddressOnStart()4651     public void testRandomizeMacAddressOnStart() throws Exception {
4652         ArgumentCaptor<MacAddress> macAddressCaptor = ArgumentCaptor.forClass(MacAddress.class);
4653         verify(mWifiNative).setStaMacAddress(anyString(), macAddressCaptor.capture());
4654         MacAddress currentMac = macAddressCaptor.getValue();
4655 
4656         assertNotEquals("The currently programmed MAC address should be different from the factory "
4657                 + "MAC address after ClientModeImpl starts",
4658                 mCmi.getFactoryMacAddress(), currentMac.toString());
4659     }
4660 
4661     /**
4662      * Verify the MAC address is being randomized at start to prevent leaking the factory MAC.
4663      */
4664     @Test
testNoRandomizeMacAddressOnStartIfMacRandomizationNotEnabled()4665     public void testNoRandomizeMacAddressOnStartIfMacRandomizationNotEnabled() throws Exception {
4666         // reset mWifiNative since initializeCmi() was called in setup()
4667         resetWifiNative();
4668 
4669         when(mWifiGlobals.isConnectedMacRandomizationEnabled()).thenReturn(false);
4670         initializeCmi();
4671         verify(mWifiNative, never()).setStaMacAddress(anyString(), any());
4672     }
4673 
4674     /**
4675      * Verify bugreport will be taken when get IP_REACHABILITY_LOST
4676      */
4677     @Test
testTakebugreportbyIpReachabilityLost()4678     public void testTakebugreportbyIpReachabilityLost() throws Exception {
4679         connect();
4680 
4681         mCmi.sendMessage(ClientModeImpl.CMD_IP_REACHABILITY_LOST);
4682         mLooper.dispatchAll();
4683         verify(mWifiDiagnostics).triggerBugReportDataCapture(
4684                 eq(WifiDiagnostics.REPORT_REASON_REACHABILITY_LOST));
4685     }
4686 
4687     /**
4688      * Verifies that WifiLastResortWatchdog is notified of FOURWAY_HANDSHAKE_TIMEOUT.
4689      */
4690     @Test
testHandshakeTimeoutUpdatesWatchdog()4691     public void testHandshakeTimeoutUpdatesWatchdog() throws Exception {
4692         // Setup CONNECT_MODE & a WifiConfiguration
4693         initializeAndAddNetworkAndVerifySuccess();
4694         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
4695         mLooper.dispatchAll();
4696         // Verifies that WifiLastResortWatchdog won't be notified
4697         // by other reason code
4698         DisconnectEventInfo disconnectEventInfo =
4699                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 2, false);
4700         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
4701         mLooper.dispatchAll();
4702 
4703         assertEquals("DisconnectedState", getCurrentState().getName());
4704         verify(mWifiLastResortWatchdog, never()).noteConnectionFailureAndTriggerIfNeeded(
4705                 eq(TEST_SSID), eq(TEST_BSSID_STR),
4706                 eq(WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION), anyBoolean());
4707 
4708         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
4709         mLooper.dispatchAll();
4710         // Verifies that WifiLastResortWatchdog be notified
4711         // for FOURWAY_HANDSHAKE_TIMEOUT.
4712         disconnectEventInfo = new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 15, false);
4713         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
4714         mLooper.dispatchAll();
4715 
4716         assertEquals("DisconnectedState", getCurrentState().getName());
4717         verify(mWifiLastResortWatchdog).noteConnectionFailureAndTriggerIfNeeded(
4718                 eq(TEST_SSID), eq(TEST_BSSID_STR),
4719                 eq(WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION), anyBoolean());
4720 
4721     }
4722 
4723     /**
4724      * Verify that WifiInfo is correctly populated after connection.
4725      */
4726     @Test
verifyWifiInfoGetNetworkSpecifierPackageName()4727     public void verifyWifiInfoGetNetworkSpecifierPackageName() throws Exception {
4728         mConnectedNetwork.fromWifiNetworkSpecifier = true;
4729         mConnectedNetwork.ephemeral = true;
4730         mConnectedNetwork.trusted = true;
4731         mConnectedNetwork.creatorName = OP_PACKAGE_NAME;
4732         connect();
4733 
4734         assertTrue(mWifiInfo.isEphemeral());
4735         assertTrue(mWifiInfo.isTrusted());
4736         assertEquals(OP_PACKAGE_NAME,
4737                 mWifiInfo.getRequestingPackageName());
4738     }
4739 
4740     /**
4741      * Verify that WifiInfo is correctly populated after connection.
4742      */
4743     @Test
verifyWifiInfoGetNetworkSuggestionPackageName()4744     public void verifyWifiInfoGetNetworkSuggestionPackageName() throws Exception {
4745         mConnectedNetwork.fromWifiNetworkSuggestion = true;
4746         mConnectedNetwork.ephemeral = true;
4747         mConnectedNetwork.trusted = true;
4748         mConnectedNetwork.creatorName = OP_PACKAGE_NAME;
4749         connect();
4750 
4751         assertTrue(mWifiInfo.isEphemeral());
4752         assertTrue(mWifiInfo.isTrusted());
4753         assertEquals(OP_PACKAGE_NAME,
4754                 mWifiInfo.getRequestingPackageName());
4755     }
4756 
4757     /**
4758      * Verify that a WifiIsUnusableEvent is logged and the current list of usability stats entries
4759      * are labeled and saved when receiving an IP reachability lost message.
4760      * @throws Exception
4761      */
4762     @Test
verifyIpReachabilityLostMsgUpdatesWifiUsabilityMetrics()4763     public void verifyIpReachabilityLostMsgUpdatesWifiUsabilityMetrics() throws Exception {
4764         connect();
4765 
4766         mCmi.sendMessage(ClientModeImpl.CMD_IP_REACHABILITY_LOST);
4767         mLooper.dispatchAll();
4768         verify(mWifiMetrics).logWifiIsUnusableEvent(WIFI_IFACE_NAME,
4769                 WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST);
4770         verify(mWifiMetrics).addToWifiUsabilityStatsList(WIFI_IFACE_NAME,
4771                 WifiUsabilityStats.LABEL_BAD,
4772                 WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST, -1);
4773     }
4774 
4775     /**
4776      * Tests that when {@link ClientModeImpl} receives a SUP_REQUEST_IDENTITY message, it responds
4777      * to the supplicant with the SIM identity.
4778      */
4779     @Test
testSupRequestIdentity_setsIdentityResponse()4780     public void testSupRequestIdentity_setsIdentityResponse() throws Exception {
4781         mConnectedNetwork = spy(WifiConfigurationTestUtil.createEapNetwork(
4782                 WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE));
4783         mConnectedNetwork.SSID = DEFAULT_TEST_SSID;
4784         String expectetIdentity = "13214561234567890@wlan.mnc456.mcc321.3gppnetwork.org";
4785 
4786         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
4787                 .thenReturn(DATA_SUBID);
4788         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
4789         when(mWifiCarrierInfoManager.getSimIdentity(any()))
4790                 .thenReturn(Pair.create(expectetIdentity, ""));
4791 
4792         triggerConnect();
4793 
4794         mCmi.sendMessage(WifiMonitor.SUP_REQUEST_IDENTITY,
4795                 0, FRAMEWORK_NETWORK_ID, DEFAULT_TEST_SSID);
4796         mLooper.dispatchAll();
4797 
4798         verify(mWifiNative).simIdentityResponse(WIFI_IFACE_NAME,
4799                 expectetIdentity, "");
4800     }
4801 
4802     /**
4803      * Verifies that WifiLastResortWatchdog is notified of DHCP failures when recevied
4804      * NETWORK_DISCONNECTION_EVENT while in L3ProvisioningState.
4805      */
4806     @Test
testDhcpFailureUpdatesWatchdog_WhenDisconnectedWhileObtainingIpAddr()4807     public void testDhcpFailureUpdatesWatchdog_WhenDisconnectedWhileObtainingIpAddr()
4808             throws Exception {
4809         initializeAndAddNetworkAndVerifySuccess();
4810 
4811         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
4812 
4813         startConnectSuccess();
4814 
4815         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
4816                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
4817         mLooper.dispatchAll();
4818 
4819         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
4820                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
4821                         SupplicantState.COMPLETED));
4822         mLooper.dispatchAll();
4823 
4824         assertEquals("L3ProvisioningState", getCurrentState().getName());
4825 
4826         // Verifies that WifiLastResortWatchdog be notified.
4827         DisconnectEventInfo disconnectEventInfo =
4828                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
4829         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
4830         mLooper.dispatchAll();
4831 
4832         assertEquals("DisconnectedState", getCurrentState().getName());
4833         verify(mWifiLastResortWatchdog).noteConnectionFailureAndTriggerIfNeeded(
4834                 eq(TEST_SSID), eq(TEST_BSSID_STR),
4835                 eq(WifiLastResortWatchdog.FAILURE_CODE_DHCP), anyBoolean());
4836     }
4837 
4838     /**
4839      * Verifies that we trigger a disconnect when the {@link WifiConfigManager}.
4840      * OnNetworkUpdateListener#onNetworkRemoved(WifiConfiguration)} is invoked.
4841      */
4842     @Test
testOnNetworkRemoved()4843     public void testOnNetworkRemoved() throws Exception {
4844         connect();
4845 
4846         WifiConfiguration removedNetwork = new WifiConfiguration();
4847         removedNetwork.networkId = FRAMEWORK_NETWORK_ID;
4848         mConfigUpdateListenerCaptor.getValue().onNetworkRemoved(removedNetwork);
4849         mLooper.dispatchAll();
4850 
4851         verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
4852         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
4853     }
4854 
4855     /**
4856      * Verifies that we trigger a disconnect when the {@link WifiConfigManager
4857      * .OnNetworkUpdateListener#onNetworkPermanentlyDisabled(WifiConfiguration, int)} is invoked.
4858      */
4859     @Test
testOnNetworkPermanentlyDisabled()4860     public void testOnNetworkPermanentlyDisabled() throws Exception {
4861         connect();
4862 
4863         WifiConfiguration disabledNetwork = new WifiConfiguration();
4864         disabledNetwork.networkId = FRAMEWORK_NETWORK_ID;
4865         mConfigUpdateListenerCaptor.getValue().onNetworkPermanentlyDisabled(disabledNetwork,
4866                 WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
4867         mLooper.dispatchAll();
4868 
4869         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
4870     }
4871 
4872     /**
4873      * Verifies that we don't trigger a disconnect when the {@link WifiConfigManager
4874      * .OnNetworkUpdateListener#onNetworkPermanentlyDisabled(WifiConfiguration, int)} is invoked.
4875      */
4876     @Test
testOnNetworkPermanentlyDisabledWithNoInternet()4877     public void testOnNetworkPermanentlyDisabledWithNoInternet() throws Exception {
4878         connect();
4879 
4880         WifiConfiguration disabledNetwork = new WifiConfiguration();
4881         disabledNetwork.networkId = FRAMEWORK_NETWORK_ID;
4882         mConfigUpdateListenerCaptor.getValue().onNetworkPermanentlyDisabled(disabledNetwork,
4883                 WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT);
4884         mLooper.dispatchAll();
4885 
4886         assertEquals("L3ConnectedState", getCurrentState().getName());
4887     }
4888 
4889     /**
4890      * Verifies that we don't trigger a disconnect when the {@link WifiConfigManager
4891      * .OnNetworkUpdateListener#onNetworkTemporarilyDisabled(WifiConfiguration, int)} is invoked.
4892      */
4893     @Test
testOnNetworkTemporarilyDisabledWithNoInternet()4894     public void testOnNetworkTemporarilyDisabledWithNoInternet() throws Exception {
4895         connect();
4896 
4897         WifiConfiguration disabledNetwork = new WifiConfiguration();
4898         disabledNetwork.networkId = FRAMEWORK_NETWORK_ID;
4899         mConfigUpdateListenerCaptor.getValue().onNetworkTemporarilyDisabled(disabledNetwork,
4900                 WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY);
4901         mLooper.dispatchAll();
4902 
4903         assertEquals("L3ConnectedState", getCurrentState().getName());
4904     }
4905 
4906     /**
4907      * Verify that MboOce/WifiDataStall enable/disable methods are called in ClientMode.
4908      */
4909     @Test
verifyMboOceWifiDataStallSetupInClientMode()4910     public void verifyMboOceWifiDataStallSetupInClientMode() throws Exception {
4911         verify(mMboOceController).enable();
4912         mCmi.stop();
4913         mLooper.dispatchAll();
4914         verify(mMboOceController).disable();
4915     }
4916 
4917     @Test
verifyWifiMonitorHandlersDeregisteredOnStop()4918     public void verifyWifiMonitorHandlersDeregisteredOnStop() throws Exception {
4919         verify(mWifiMonitor, atLeastOnce())
4920                 .registerHandler(eq(WIFI_IFACE_NAME), anyInt(), any());
4921         verify(mWifiMetrics).registerForWifiMonitorEvents(WIFI_IFACE_NAME);
4922         verify(mWifiLastResortWatchdog).registerForWifiMonitorEvents(WIFI_IFACE_NAME);
4923 
4924         mCmi.stop();
4925         mLooper.dispatchAll();
4926 
4927         verify(mWifiMonitor, atLeastOnce())
4928                 .deregisterHandler(eq(WIFI_IFACE_NAME), anyInt(), any());
4929         verify(mWifiMetrics).deregisterForWifiMonitorEvents(WIFI_IFACE_NAME);
4930         verify(mWifiLastResortWatchdog).deregisterForWifiMonitorEvents(WIFI_IFACE_NAME);
4931     }
4932 
4933     @Test
onBluetoothConnectionStateChanged()4934     public void onBluetoothConnectionStateChanged() throws Exception {
4935         // reset mWifiNative since initializeCmi() was called in setup()
4936         resetWifiNative();
4937 
4938         when(mWifiGlobals.isBluetoothConnected()).thenReturn(false);
4939         initializeCmi();
4940         verify(mWifiNative).setBluetoothCoexistenceScanMode(any(), eq(false));
4941 
4942         when(mWifiGlobals.isBluetoothConnected()).thenReturn(true);
4943         mCmi.onBluetoothConnectionStateChanged();
4944         mLooper.dispatchAll();
4945         verify(mWifiNative).setBluetoothCoexistenceScanMode(any(), eq(true));
4946 
4947         when(mWifiGlobals.isBluetoothConnected()).thenReturn(false);
4948         mCmi.onBluetoothConnectionStateChanged();
4949         mLooper.dispatchAll();
4950         verify(mWifiNative, times(2)).setBluetoothCoexistenceScanMode(any(), eq(false));
4951     }
4952 
4953     /**
4954      * Test that handleBssTransitionRequest() blocklist the BSS upon
4955      * receiving BTM request frame that contains MBO-OCE IE with an
4956      * association retry delay attribute.
4957      */
4958     @Test
testBtmFrameWithMboAssocretryDelayBlockListTheBssid()4959     public void testBtmFrameWithMboAssocretryDelayBlockListTheBssid() throws Exception {
4960         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
4961         connect();
4962 
4963         MboOceController.BtmFrameData btmFrmData = new MboOceController.BtmFrameData();
4964 
4965         btmFrmData.mStatus = MboOceConstants.BTM_RESPONSE_STATUS_REJECT_UNSPECIFIED;
4966         btmFrmData.mBssTmDataFlagsMask = MboOceConstants.BTM_DATA_FLAG_DISASSOCIATION_IMMINENT
4967                 | MboOceConstants.BTM_DATA_FLAG_MBO_ASSOC_RETRY_DELAY_INCLUDED;
4968         btmFrmData.mBlockListDurationMs = 60000;
4969 
4970         mCmi.sendMessage(WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE, btmFrmData);
4971         mLooper.dispatchAll();
4972 
4973         verify(mWifiMetrics, times(1)).incrementSteeringRequestCountIncludingMboAssocRetryDelay();
4974         verify(mWifiBlocklistMonitor).blockBssidForDurationMs(eq(TEST_BSSID_STR), eq(TEST_SSID),
4975                 eq(btmFrmData.mBlockListDurationMs), anyInt(), anyInt());
4976     }
4977 
4978     /**
4979      * Test that handleBssTransitionRequest() blocklist the BSS upon
4980      * receiving BTM request frame that contains disassociation imminent bit
4981      * set to 1.
4982      */
4983     @Test
testBtmFrameWithDisassocImminentBitBlockListTheBssid()4984     public void testBtmFrameWithDisassocImminentBitBlockListTheBssid() throws Exception {
4985         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
4986         connect();
4987 
4988         MboOceController.BtmFrameData btmFrmData = new MboOceController.BtmFrameData();
4989 
4990         btmFrmData.mStatus = MboOceConstants.BTM_RESPONSE_STATUS_ACCEPT;
4991         btmFrmData.mBssTmDataFlagsMask = MboOceConstants.BTM_DATA_FLAG_DISASSOCIATION_IMMINENT;
4992 
4993         mCmi.sendMessage(WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE, btmFrmData);
4994         mLooper.dispatchAll();
4995 
4996         verify(mWifiMetrics, never()).incrementSteeringRequestCountIncludingMboAssocRetryDelay();
4997         verify(mWifiBlocklistMonitor).blockBssidForDurationMs(eq(TEST_BSSID_STR), eq(TEST_SSID),
4998                 eq(MboOceConstants.DEFAULT_BLOCKLIST_DURATION_MS), anyInt(), anyInt());
4999     }
5000 
5001     /**
5002      * Test that handleBssTransitionRequest() trigger force scan for
5003      * network selection when status code is REJECT.
5004      */
5005     @Test
testBTMRequestRejectTriggerNetworkSelction()5006     public void testBTMRequestRejectTriggerNetworkSelction() throws Exception {
5007         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
5008         connect();
5009 
5010         MboOceController.BtmFrameData btmFrmData = new MboOceController.BtmFrameData();
5011 
5012         btmFrmData.mStatus = MboOceConstants.BTM_RESPONSE_STATUS_REJECT_UNSPECIFIED;
5013         btmFrmData.mBssTmDataFlagsMask = MboOceConstants.BTM_DATA_FLAG_DISASSOCIATION_IMMINENT
5014                 | MboOceConstants.BTM_DATA_FLAG_BSS_TERMINATION_INCLUDED
5015                 | MboOceConstants.BTM_DATA_FLAG_MBO_CELL_DATA_CONNECTION_PREFERENCE_INCLUDED;
5016         btmFrmData.mBlockListDurationMs = 60000;
5017 
5018         mCmi.sendMessage(WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE, btmFrmData);
5019         mLooper.dispatchAll();
5020 
5021         verify(mWifiBlocklistMonitor, never()).blockBssidForDurationMs(eq(TEST_BSSID_STR),
5022                 eq(TEST_SSID), eq(btmFrmData.mBlockListDurationMs), anyInt(), anyInt());
5023         verify(mWifiConnectivityManager).forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
5024         verify(mWifiMetrics, times(1)).incrementMboCellularSwitchRequestCount();
5025         verify(mWifiMetrics, times(1))
5026                 .incrementForceScanCountDueToSteeringRequest();
5027 
5028     }
5029 
5030     /**
5031      * Test that handleBssTransitionRequest() does not trigger force
5032      * scan when status code is accept.
5033      */
5034     @Test
testBTMRequestAcceptDoNotTriggerNetworkSelction()5035     public void testBTMRequestAcceptDoNotTriggerNetworkSelction() throws Exception {
5036         // Connect to network with |TEST_BSSID_STR|, |sFreq|.
5037         connect();
5038 
5039         MboOceController.BtmFrameData btmFrmData = new MboOceController.BtmFrameData();
5040 
5041         btmFrmData.mStatus = MboOceConstants.BTM_RESPONSE_STATUS_ACCEPT;
5042         btmFrmData.mBssTmDataFlagsMask = MboOceConstants.BTM_DATA_FLAG_DISASSOCIATION_IMMINENT;
5043 
5044         mCmi.sendMessage(WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE, btmFrmData);
5045         mLooper.dispatchAll();
5046 
5047         verify(mWifiConnectivityManager, never())
5048                 .forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
5049     }
5050 
createIE(int id, byte[] bytes)5051     private static ScanResult.InformationElement createIE(int id, byte[] bytes) {
5052         ScanResult.InformationElement ie = new ScanResult.InformationElement();
5053         ie.id = id;
5054         ie.bytes = bytes;
5055         return ie;
5056     }
5057 
5058     /**
5059      * Helper function for setting up fils test.
5060      *
5061      * @param isDriverSupportFils true if driver support fils.
5062      * @return wifi configuration.
5063      */
setupFilsTest(boolean isDriverSupportFils)5064     private WifiConfiguration setupFilsTest(boolean isDriverSupportFils) {
5065         WifiConfiguration config = new WifiConfiguration();
5066         config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
5067         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
5068         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
5069         config.SSID = ScanResultUtil.createQuotedSSID(sFilsSsid);
5070         config.networkId = 1;
5071         config.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS);
5072         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
5073 
5074         when(mWifiConfigManager.getConfiguredNetworkWithoutMasking(anyInt())).thenReturn(config);
5075         if (isDriverSupportFils) {
5076             when(mWifiNative.getSupportedFeatureSet(WIFI_IFACE_NAME)).thenReturn(
5077                     WifiManager.WIFI_FEATURE_FILS_SHA256 | WifiManager.WIFI_FEATURE_FILS_SHA384);
5078         } else {
5079             when(mWifiNative.getSupportedFeatureSet(WIFI_IFACE_NAME)).thenReturn((long) 0);
5080         }
5081 
5082         return config;
5083     }
5084 
5085     /**
5086      * Helper function for setting up a scan result with FILS supported AP.
5087      *
5088      */
setupFilsEnabledApInScanResult()5089     private void setupFilsEnabledApInScanResult() {
5090         String caps = "[WPA2-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP]"
5091                 + "[RSN-EAP/SHA1+EAP/SHA256+EAP-FILS-SHA256-CCMP][ESS]";
5092         ScanResult scanResult = new ScanResult(WifiSsid.createFromAsciiEncoded(sFilsSsid),
5093                 sFilsSsid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true);
5094         ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID,
5095                 sFilsSsid.getBytes(StandardCharsets.UTF_8));
5096         scanResult.informationElements = new ScanResult.InformationElement[]{ie};
5097         when(mScanRequestProxy.getScanResults()).thenReturn(Arrays.asList(scanResult));
5098         when(mScanRequestProxy.getScanResult(eq(TEST_BSSID_STR))).thenReturn(scanResult);
5099     }
5100 
5101 
5102     /**
5103      * Helper function to send CMD_START_FILS_CONNECTION along with HLP IEs.
5104      *
5105      */
prepareFilsHlpPktAndSendStartConnect()5106     private void prepareFilsHlpPktAndSendStartConnect() {
5107         Layer2PacketParcelable l2Packet = new Layer2PacketParcelable();
5108         l2Packet.dstMacAddress = TEST_GLOBAL_MAC_ADDRESS;
5109         l2Packet.payload = new byte[] {0x00, 0x12, 0x13, 0x00, 0x12, 0x13, 0x00, 0x12, 0x13,
5110                 0x12, 0x13, 0x00, 0x12, 0x13, 0x00, 0x12, 0x13, 0x00, 0x12, 0x13, 0x55, 0x66};
5111         mCmi.sendMessage(ClientModeImpl.CMD_START_FILS_CONNECTION, 0, 0,
5112                 Collections.singletonList(l2Packet));
5113         mLooper.dispatchAll();
5114     }
5115 
5116     /**
5117      * Verifies that while connecting to AP, the logic looks into the scan result and
5118      * looks for AP matching the network type and ssid and update the wificonfig with FILS
5119      * AKM if supported.
5120      *
5121      * @throws Exception
5122      */
5123     @Test
testFilsAKMUpdateBeforeConnect()5124     public void testFilsAKMUpdateBeforeConnect() throws Exception {
5125         initializeAndAddNetworkAndVerifySuccess();
5126         WifiConfiguration config = setupFilsTest(true);
5127         setupFilsEnabledApInScanResult();
5128 
5129         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5130         mLooper.dispatchAll();
5131 
5132         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256));
5133         verify(mWifiNative, never()).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
5134     }
5135 
5136     /**
5137      * Verifies that while connecting to AP, framework updates the wifi config with
5138      * FILS AKM only if underlying driver support FILS feature.
5139      *
5140      * @throws Exception
5141      */
5142     @Test
testFilsAkmIsNotAddedinWifiConfigIfDriverDoesNotSupportFils()5143     public void testFilsAkmIsNotAddedinWifiConfigIfDriverDoesNotSupportFils() throws Exception {
5144         initializeAndAddNetworkAndVerifySuccess();
5145         WifiConfiguration config = setupFilsTest(false);
5146         setupFilsEnabledApInScanResult();
5147 
5148         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5149         mLooper.dispatchAll();
5150 
5151         assertFalse(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256));
5152         verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
5153     }
5154 
5155 
5156     /**
5157      * Verifies that the HLP (DHCP) packets are send to wpa_supplicant
5158      * prior to Fils connection.
5159      *
5160      * @throws Exception
5161      */
5162     @Test
testFilsHlpUpdateBeforeFilsConnection()5163     public void testFilsHlpUpdateBeforeFilsConnection() throws Exception {
5164         initializeAndAddNetworkAndVerifySuccess();
5165         WifiConfiguration config = setupFilsTest(true);
5166         setupFilsEnabledApInScanResult();
5167 
5168         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5169         mLooper.dispatchAll();
5170 
5171         prepareFilsHlpPktAndSendStartConnect();
5172 
5173         verify(mWifiNative).flushAllHlp(eq(WIFI_IFACE_NAME));
5174         verify(mWifiNative).addHlpReq(eq(WIFI_IFACE_NAME), any(), any());
5175         verify(mWifiNative).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
5176     }
5177 
5178     /**
5179      * Verifies that an association rejection in first FILS connect attempt doesn't block
5180      * the second connection attempt.
5181      *
5182      * @throws Exception
5183      */
5184     @Test
testFilsSecondConnectAttemptIsNotBLockedAfterAssocReject()5185     public void testFilsSecondConnectAttemptIsNotBLockedAfterAssocReject() throws Exception {
5186         initializeAndAddNetworkAndVerifySuccess();
5187         WifiConfiguration config = setupFilsTest(true);
5188         setupFilsEnabledApInScanResult();
5189 
5190         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5191         mLooper.dispatchAll();
5192 
5193         prepareFilsHlpPktAndSendStartConnect();
5194 
5195         verify(mWifiNative, times(1)).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
5196 
5197         mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT,
5198                 new AssocRejectEventInfo(TEST_SSID, TEST_BSSID_STR, 2, false));
5199         mLooper.dispatchAll();
5200 
5201         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5202         mLooper.dispatchAll();
5203         prepareFilsHlpPktAndSendStartConnect();
5204 
5205         verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
5206     }
5207 
5208     /**
5209      * Verifies Fils connection.
5210      *
5211      * @throws Exception
5212      */
5213     @Test
testFilsConnection()5214     public void testFilsConnection() throws Exception {
5215         initializeAndAddNetworkAndVerifySuccess();
5216         WifiConfiguration config = setupFilsTest(true);
5217         setupFilsEnabledApInScanResult();
5218 
5219         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5220         mLooper.dispatchAll();
5221 
5222         prepareFilsHlpPktAndSendStartConnect();
5223 
5224         verify(mWifiMetrics, times(1)).incrementConnectRequestWithFilsAkmCount();
5225 
5226         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
5227                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, true));
5228         mLooper.dispatchAll();
5229 
5230         verify(mWifiMetrics, times(1)).incrementL2ConnectionThroughFilsAuthCount();
5231 
5232         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5233                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(sFilsSsid),
5234                 TEST_BSSID_STR, SupplicantState.COMPLETED));
5235         mLooper.dispatchAll();
5236 
5237         assertEquals("L3ProvisioningState", getCurrentState().getName());
5238 
5239         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
5240         dhcpResults.baseConfiguration = new StaticIpConfiguration();
5241         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
5242         dhcpResults.baseConfiguration.ipAddress =
5243                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
5244         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
5245         dhcpResults.leaseDuration = 3600;
5246 
5247         injectDhcpSuccess(dhcpResults);
5248         mLooper.dispatchAll();
5249 
5250         WifiInfo wifiInfo = mWifiInfo;
5251         assertNotNull(wifiInfo);
5252         assertEquals(TEST_BSSID_STR, wifiInfo.getBSSID());
5253         assertTrue(WifiSsid.createFromAsciiEncoded(sFilsSsid).equals(wifiInfo.getWifiSsid()));
5254         assertEquals("L3ConnectedState", getCurrentState().getName());
5255     }
5256 
5257     /**
5258      * Tests the wifi info is updated correctly for connecting network.
5259      */
5260     @Test
testWifiInfoOnConnectingNextNetwork()5261     public void testWifiInfoOnConnectingNextNetwork() throws Exception {
5262         mConnectedNetwork.ephemeral = true;
5263         mConnectedNetwork.trusted = true;
5264         mConnectedNetwork.oemPaid = true;
5265         mConnectedNetwork.oemPrivate = true;
5266         mConnectedNetwork.carrierMerged = true;
5267         mConnectedNetwork.osu = true;
5268         mConnectedNetwork.subscriptionId = DATA_SUBID;
5269 
5270         triggerConnect();
5271         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
5272                 .thenReturn(mScanDetailCache);
5273 
5274         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
5275                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
5276         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
5277                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
5278 
5279         // before the fist success connection, there is no valid wifi info.
5280         assertEquals(WifiConfiguration.INVALID_NETWORK_ID, mWifiInfo.getNetworkId());
5281 
5282         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5283                 new StateChangeResult(FRAMEWORK_NETWORK_ID,
5284                     TEST_WIFI_SSID, TEST_BSSID_STR, SupplicantState.ASSOCIATED));
5285         mLooper.dispatchAll();
5286 
5287         // retrieve correct wifi info on receiving the supplicant state change event.
5288         assertEquals(FRAMEWORK_NETWORK_ID, mWifiInfo.getNetworkId());
5289         assertEquals(mConnectedNetwork.ephemeral, mWifiInfo.isEphemeral());
5290         assertEquals(mConnectedNetwork.trusted, mWifiInfo.isTrusted());
5291         assertEquals(mConnectedNetwork.osu, mWifiInfo.isOsuAp());
5292         if (SdkLevel.isAtLeastS()) {
5293             assertEquals(mConnectedNetwork.oemPaid, mWifiInfo.isOemPaid());
5294             assertEquals(mConnectedNetwork.oemPrivate, mWifiInfo.isOemPrivate());
5295             assertEquals(mConnectedNetwork.carrierMerged, mWifiInfo.isCarrierMerged());
5296             assertEquals(DATA_SUBID, mWifiInfo.getSubscriptionId());
5297         }
5298     }
5299 
5300     /**
5301      * Verify that we disconnect when we mark a previous unmetered network metered.
5302      */
5303     @Test
verifyDisconnectOnMarkingNetworkMetered()5304     public void verifyDisconnectOnMarkingNetworkMetered() throws Exception {
5305         connect();
5306         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5307             assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5308         });
5309 
5310         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5311         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
5312 
5313         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5314         mLooper.dispatchAll();
5315         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
5316         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
5317                 eq(StaEvent.DISCONNECT_NETWORK_METERED));
5318     }
5319 
5320     /**
5321      * Verify that we only update capabilites when we mark a previous unmetered network metered.
5322      */
5323     @Test
verifyUpdateCapabilitiesOnMarkingNetworkUnmetered()5324     public void verifyUpdateCapabilitiesOnMarkingNetworkUnmetered() throws Exception {
5325         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
5326         connect();
5327         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5328             assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5329         });
5330         reset(mWifiNetworkAgent);
5331 
5332         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5333         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
5334 
5335         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5336         mLooper.dispatchAll();
5337         assertEquals("L3ConnectedState", getCurrentState().getName());
5338 
5339         expectNetworkAgentUpdateCapabilities((cap) -> {
5340             assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5341         });
5342     }
5343 
5344 
5345     /**
5346      * Verify that we disconnect when we mark a previous unmetered network metered.
5347      */
5348     @Test
verifyDisconnectOnMarkingNetworkAutoMeteredWithMeteredHint()5349     public void verifyDisconnectOnMarkingNetworkAutoMeteredWithMeteredHint() throws Exception {
5350         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
5351         connect();
5352         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5353             assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5354         });
5355         reset(mWifiNetworkAgent);
5356 
5357         // Mark network metered none.
5358         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5359         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
5360 
5361         // Set metered hint in WifiInfo (either via DHCP or ScanResult IE).
5362         WifiInfo wifiInfo = mWifiInfo;
5363         wifiInfo.setMeteredHint(true);
5364 
5365         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5366         mLooper.dispatchAll();
5367         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
5368     }
5369 
5370     /**
5371      * Verify that we only update capabilites when we mark a previous unmetered network metered.
5372      */
5373     @Test
verifyUpdateCapabilitiesOnMarkingNetworkAutoMeteredWithoutMeteredHint()5374     public void verifyUpdateCapabilitiesOnMarkingNetworkAutoMeteredWithoutMeteredHint()
5375             throws Exception {
5376         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
5377         connect();
5378         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5379             assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5380         });
5381         reset(mWifiNetworkAgent);
5382 
5383         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5384         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
5385 
5386         // Reset metered hint in WifiInfo.
5387         WifiInfo wifiInfo = mWifiInfo;
5388         wifiInfo.setMeteredHint(false);
5389 
5390         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5391         mLooper.dispatchAll();
5392         assertEquals("L3ConnectedState", getCurrentState().getName());
5393 
5394         expectNetworkAgentUpdateCapabilities((cap) -> {
5395             assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5396         });
5397     }
5398 
5399     /**
5400      * Verify that we do nothing on no metered change.
5401      */
5402     @Test
verifyDoNothingMarkingNetworkAutoMeteredWithMeteredHint()5403     public void verifyDoNothingMarkingNetworkAutoMeteredWithMeteredHint() throws Exception {
5404         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
5405         connect();
5406         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5407             assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5408         });
5409         reset(mWifiNetworkAgent);
5410 
5411         // Mark network metered none.
5412         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5413         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
5414 
5415         // Set metered hint in WifiInfo (either via DHCP or ScanResult IE).
5416         WifiInfo wifiInfo = mWifiInfo;
5417         wifiInfo.setMeteredHint(true);
5418 
5419         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5420         mLooper.dispatchAll();
5421         assertEquals("L3ConnectedState", getCurrentState().getName());
5422 
5423         verifyNoMoreInteractions(mWifiNetworkAgent);
5424     }
5425 
5426     /**
5427      * Verify that we do nothing on no metered change.
5428      */
5429     @Test
verifyDoNothingMarkingNetworkAutoMeteredWithoutMeteredHint()5430     public void verifyDoNothingMarkingNetworkAutoMeteredWithoutMeteredHint() throws Exception {
5431         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
5432         connect();
5433         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
5434             assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
5435         });
5436         reset(mWifiNetworkAgent);
5437 
5438         // Mark network metered none.
5439         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5440         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
5441 
5442         // Reset metered hint in WifiInfo.
5443         WifiInfo wifiInfo = mWifiInfo;
5444         wifiInfo.setMeteredHint(false);
5445 
5446         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5447         mLooper.dispatchAll();
5448         assertEquals("L3ConnectedState", getCurrentState().getName());
5449 
5450         verifyNoMoreInteractions(mWifiNetworkAgent);
5451     }
5452 
5453     /*
5454      * Verify that network cached data is cleared correctly in
5455      * disconnected state.
5456      */
5457     @Test
testNetworkCachedDataIsClearedCorrectlyInDisconnectedState()5458     public void testNetworkCachedDataIsClearedCorrectlyInDisconnectedState() throws Exception {
5459         // Setup CONNECT_MODE & a WifiConfiguration
5460         initializeAndAddNetworkAndVerifySuccess();
5461         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5462         mLooper.dispatchAll();
5463 
5464         // got UNSPECIFIED during this connection attempt
5465         DisconnectEventInfo disconnectEventInfo =
5466                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 1, false);
5467         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5468         mLooper.dispatchAll();
5469 
5470         assertEquals("DisconnectedState", getCurrentState().getName());
5471         verify(mWifiNative, never()).removeNetworkCachedData(anyInt());
5472 
5473         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
5474         mLooper.dispatchAll();
5475         // got 4WAY_HANDSHAKE_TIMEOUT during this connection attempt
5476         disconnectEventInfo = new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 15, false);
5477         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5478         mLooper.dispatchAll();
5479 
5480         assertEquals("DisconnectedState", getCurrentState().getName());
5481         verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
5482     }
5483 
5484     /*
5485      * Verify that network cached data is cleared correctly in
5486      * disconnected state.
5487      */
5488     @Test
testNetworkCachedDataIsClearedCorrectlyInL3ProvisioningState()5489     public void testNetworkCachedDataIsClearedCorrectlyInL3ProvisioningState() throws Exception {
5490         initializeAndAddNetworkAndVerifySuccess();
5491 
5492         verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
5493 
5494         startConnectSuccess();
5495 
5496         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
5497                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
5498         mLooper.dispatchAll();
5499 
5500         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5501                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
5502                         SupplicantState.COMPLETED));
5503         mLooper.dispatchAll();
5504 
5505         assertEquals("L3ProvisioningState", getCurrentState().getName());
5506 
5507         // got 4WAY_HANDSHAKE_TIMEOUT during this connection attempt
5508         DisconnectEventInfo disconnectEventInfo =
5509                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 15, false);
5510         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5511         mLooper.dispatchAll();
5512 
5513         verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
5514     }
5515 
5516     /*
5517      * Verify that network cached data is NOT cleared in L3ConnectedState.
5518      */
5519     @Test
testNetworkCachedDataIsClearedIf4WayHandshakeFailure()5520     public void testNetworkCachedDataIsClearedIf4WayHandshakeFailure() throws Exception {
5521         when(mWifiScoreCard.detectAbnormalDisconnection(any()))
5522                 .thenReturn(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL);
5523         InOrder inOrderWifiLockManager = inOrder(mWifiLockManager);
5524         connect();
5525         inOrderWifiLockManager.verify(mWifiLockManager)
5526                 .updateWifiClientConnected(mClientModeManager, true);
5527 
5528         // got 4WAY_HANDSHAKE_TIMEOUT
5529         DisconnectEventInfo disconnectEventInfo =
5530                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 15, false);
5531         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5532         mLooper.dispatchAll();
5533         verify(mWifiNative, never()).removeNetworkCachedData(anyInt());
5534     }
5535 
5536     /**
5537      * Verify that network cached data is cleared on updating a network.
5538      */
5539     @Test
testNetworkCachedDataIsClearedOnUpdatingNetwork()5540     public void testNetworkCachedDataIsClearedOnUpdatingNetwork() throws Exception {
5541         WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
5542         mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
5543 
5544         mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
5545         mLooper.dispatchAll();
5546         verify(mWifiNative).removeNetworkCachedData(eq(oldConfig.networkId));
5547     }
5548 
5549 
5550     @Test
testVerifyWifiInfoStateOnFrameworkDisconnect()5551     public void testVerifyWifiInfoStateOnFrameworkDisconnect() throws Exception {
5552         connect();
5553 
5554         assertEquals(mWifiInfo.getSupplicantState(), SupplicantState.COMPLETED);
5555 
5556         // Now trigger disconnect
5557         mCmi.disconnect();
5558         mLooper.dispatchAll();
5559 
5560         // get disconnect event
5561         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5562                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
5563                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
5564         mLooper.dispatchAll();
5565 
5566         assertEquals(mWifiInfo.getSupplicantState(), SupplicantState.DISCONNECTED);
5567     }
5568 
5569     @Test
testVerifyWifiInfoStateOnFrameworkDisconnectButMissingDisconnectEvent()5570     public void testVerifyWifiInfoStateOnFrameworkDisconnectButMissingDisconnectEvent()
5571             throws Exception {
5572         connect();
5573 
5574         assertEquals(mWifiInfo.getSupplicantState(), SupplicantState.COMPLETED);
5575 
5576         // Now trigger disconnect
5577         mCmi.disconnect();
5578         mLooper.dispatchAll();
5579 
5580         // missing disconnect event, but got supplicant state change with disconnect state instead.
5581         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5582                 new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(mConnectedNetwork.SSID),
5583                         TEST_BSSID_STR, SupplicantState.DISCONNECTED));
5584         mLooper.dispatchAll();
5585 
5586         assertEquals(mWifiInfo.getSupplicantState(), SupplicantState.DISCONNECTED);
5587     }
5588 
5589     /**
5590      * Ensures that we only disable the current network & set MAC address only when we exit
5591      * ConnectingState.
5592      * @throws Exception
5593      */
5594     @Test
testDisableNetworkOnExitingConnectingOrConnectedState()5595     public void testDisableNetworkOnExitingConnectingOrConnectedState() throws Exception {
5596         connect();
5597         String oldSsid = mConnectedNetwork.SSID;
5598 
5599         // Trigger connection to a different network
5600         mConnectedNetwork.SSID = oldSsid.concat("blah");
5601         mConnectedNetwork.networkId++;
5602         mConnectedNetwork.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
5603         setupAndStartConnectSequence(mConnectedNetwork);
5604 
5605         // Send disconnect event for the old network.
5606         DisconnectEventInfo disconnectEventInfo =
5607                 new DisconnectEventInfo(oldSsid, TEST_BSSID_STR, 0, false);
5608         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5609         mLooper.dispatchAll();
5610 
5611         assertEquals("L2ConnectingState", getCurrentState().getName());
5612         // Since we remain in connecting state, we should not disable the network or set random MAC
5613         // address on disconnect.
5614         verify(mWifiNative, never()).disableNetwork(WIFI_IFACE_NAME);
5615         // Set MAC address thrice - once at bootup, twice for the 2 connections.
5616         verify(mWifiNative, times(3)).setStaMacAddress(eq(WIFI_IFACE_NAME), any());
5617 
5618         // Send disconnect event for the new network.
5619         disconnectEventInfo =
5620                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
5621         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5622         mLooper.dispatchAll();
5623 
5624         verify(mWifiNative).disableNetwork(WIFI_IFACE_NAME);
5625         // Set MAC address thrice - once at bootup, twice for the connections,
5626         // once for the disconnect.
5627         verify(mWifiNative, times(4)).setStaMacAddress(eq(WIFI_IFACE_NAME), any());
5628     }
5629 
5630     @Test
testIpReachabilityLostAndRoamEventsRace()5631     public void testIpReachabilityLostAndRoamEventsRace() throws Exception {
5632         connect();
5633         expectRegisterNetworkAgent((agentConfig) -> { }, (cap) -> { });
5634         reset(mWifiNetworkAgent);
5635 
5636         // Trigger ip reachability loss and ensure we trigger a disconnect.
5637         mCmi.sendMessage(ClientModeImpl.CMD_IP_REACHABILITY_LOST);
5638         mLooper.dispatchAll();
5639         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
5640 
5641         // Now send a network connection (indicating a roam) event before we get the disconnect
5642         // event.
5643         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
5644                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR, false));
5645         mLooper.dispatchAll();
5646         // ensure that we ignored the transient roam while we're disconnecting.
5647         verifyNoMoreInteractions(mWifiNetworkAgent);
5648 
5649         // Now send the disconnect event and ensure that we transition to "DisconnectedState".
5650         DisconnectEventInfo disconnectEventInfo =
5651                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
5652         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5653         mLooper.dispatchAll();
5654         assertEquals("DisconnectedState", getCurrentState().getName());
5655         verify(mWifiNetworkAgent).unregister();
5656 
5657         verifyNoMoreInteractions(mWifiNetworkAgent);
5658     }
5659 
5660     @Test
testConnectionWhileDisconnecting()5661     public void testConnectionWhileDisconnecting() throws Exception {
5662         connect();
5663 
5664         // Trigger a disconnect event.
5665         mCmi.disconnect();
5666         mLooper.dispatchAll();
5667         assertEquals("L3ConnectedState", getCurrentState().getName());
5668 
5669         // Trigger a new connection before the NETWORK_DISCONNECTION_EVENT comes in.
5670         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
5671         config.networkId = FRAMEWORK_NETWORK_ID + 1;
5672         setupAndStartConnectSequence(config);
5673         // Ensure that we triggered the connection attempt.
5674         validateSuccessfulConnectSequence(config);
5675 
5676         // Now trigger the disconnect event for the previous disconnect and ensure we handle it
5677         // correctly and remain in ConnectingState.
5678         DisconnectEventInfo disconnectEventInfo =
5679                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
5680         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5681         mLooper.dispatchAll();
5682         assertEquals("L2ConnectingState", mCmi.getCurrentState().getName());
5683     }
5684 
5685     @Test
testConnectionWatchdog()5686     public void testConnectionWatchdog() throws Exception {
5687         triggerConnect();
5688         Log.i(TAG, "Triggering Connect done");
5689 
5690         // Simulate watchdog timeout and ensure we retuned to disconnected state.
5691         mLooper.moveTimeForward(ClientModeImpl.CONNECTING_WATCHDOG_TIMEOUT_MS + 5L);
5692         mLooper.dispatchAll();
5693 
5694         verify(mWifiNative).disableNetwork(WIFI_IFACE_NAME);
5695         assertEquals("DisconnectedState", mCmi.getCurrentState().getName());
5696     }
5697 
5698     @Test
testRoamAfterConnectDoesNotChangeNetworkInfoInNetworkStateChangeBroadcast()5699     public void testRoamAfterConnectDoesNotChangeNetworkInfoInNetworkStateChangeBroadcast()
5700             throws Exception {
5701         connect();
5702 
5703         // The last NETWORK_STATE_CHANGED_ACTION should be to mark the network connected.
5704         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
5705         verify(mContext, atLeastOnce()).sendStickyBroadcastAsUser(intentCaptor.capture(), any());
5706         Intent intent = intentCaptor.getValue();
5707         assertNotNull(intent);
5708         assertEquals(WifiManager.NETWORK_STATE_CHANGED_ACTION, intent.getAction());
5709         NetworkInfo networkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
5710         assertTrue(networkInfo.isConnected());
5711 
5712         reset(mContext);
5713         when(mContext.getResources()).thenReturn(mResources);
5714 
5715         // send roam event
5716         mCmi.sendMessage(WifiMonitor.ASSOCIATED_BSSID_EVENT, 0, 0, TEST_BSSID_STR1);
5717         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5718                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR1,
5719                         SupplicantState.COMPLETED));
5720         mLooper.dispatchAll();
5721 
5722         verify(mContext, atLeastOnce()).sendStickyBroadcastAsUser(intentCaptor.capture(), any());
5723         intent = intentCaptor.getValue();
5724         assertNotNull(intent);
5725         assertEquals(WifiManager.NETWORK_STATE_CHANGED_ACTION, intent.getAction());
5726         networkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
5727         assertTrue(networkInfo.isConnected());
5728     }
5729 
5730 
5731     /**
5732      * Ensure that {@link ClientModeImpl#dump(FileDescriptor, PrintWriter, String[])}
5733      * {@link WifiNative#getWifiLinkLayerStats(String)}, at least once before calling
5734      * {@link WifiScoreReport#dump(FileDescriptor, PrintWriter, String[])}.
5735      *
5736      * This ensures that WifiScoreReport will always get updated RSSI and link layer stats before
5737      * dumping during a bug report, no matter if the screen is on or not.
5738      */
5739     @Test
testWifiScoreReportDump()5740     public void testWifiScoreReportDump() throws Exception {
5741         connect();
5742 
5743         mLooper.startAutoDispatch();
5744         mCmi.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null);
5745         mLooper.stopAutoDispatchAndIgnoreExceptions();
5746 
5747         InOrder inOrder = inOrder(mWifiNative, mWifiScoreReport);
5748 
5749         inOrder.verify(mWifiNative).getWifiLinkLayerStats(any());
5750         inOrder.verify(mWifiScoreReport).dump(any(), any(), any());
5751     }
5752 
5753     @Test
clearRequestingPackageNameInWifiInfoOnConnectionFailure()5754     public void clearRequestingPackageNameInWifiInfoOnConnectionFailure() throws Exception {
5755         mConnectedNetwork.fromWifiNetworkSpecifier = true;
5756         mConnectedNetwork.ephemeral = true;
5757         mConnectedNetwork.creatorName = OP_PACKAGE_NAME;
5758 
5759         triggerConnect();
5760 
5761         // association completed
5762         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5763                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
5764                         SupplicantState.ASSOCIATED));
5765         mLooper.dispatchAll();
5766 
5767         assertTrue(mWifiInfo.isEphemeral());
5768         assertEquals(OP_PACKAGE_NAME, mWifiInfo.getRequestingPackageName());
5769 
5770         // fail the connection.
5771         DisconnectEventInfo disconnectEventInfo =
5772                 new DisconnectEventInfo(mConnectedNetwork.SSID, TEST_BSSID_STR, 0, false);
5773         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
5774         mLooper.dispatchAll();
5775 
5776         assertFalse(mWifiInfo.isEphemeral());
5777         assertNull(mWifiInfo.getRequestingPackageName());
5778     }
5779 
5780     @Test
handleAssociationRejectionWhenRoaming()5781     public void handleAssociationRejectionWhenRoaming() throws Exception {
5782         connect();
5783 
5784         assertTrue(SupplicantState.isConnecting(mWifiInfo.getSupplicantState()));
5785 
5786         when(mWifiNative.roamToNetwork(any(), any())).thenReturn(true);
5787 
5788         // Trigger roam to a BSSID.
5789         mCmi.startRoamToNetwork(FRAMEWORK_NETWORK_ID, TEST_BSSID_STR1);
5790         mLooper.dispatchAll();
5791 
5792 
5793         assertEquals(TEST_BSSID_STR1, mCmi.getConnectingBssid());
5794         assertEquals(FRAMEWORK_NETWORK_ID, mCmi.getConnectingWifiConfiguration().networkId);
5795 
5796         verify(mWifiNative).roamToNetwork(any(), any());
5797         assertEquals("RoamingState", getCurrentState().getName());
5798 
5799         // fail the connection.
5800         mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
5801                 new StateChangeResult(0, TEST_WIFI_SSID, TEST_BSSID_STR,
5802                         SupplicantState.DISCONNECTED));
5803         mLooper.dispatchAll();
5804 
5805         // Ensure we reset WifiInfo fields.
5806         assertFalse(SupplicantState.isConnecting(mWifiInfo.getSupplicantState()));
5807     }
5808 
5809     @Test
testOemPaidNetworkCapability()5810     public void testOemPaidNetworkCapability() throws Exception {
5811         // oemPaid introduced in S, not applicable to R
5812         assumeTrue(SdkLevel.isAtLeastS());
5813         mConnectedNetwork.oemPaid = true;
5814         connect();
5815         expectRegisterNetworkAgent((agentConfig) -> { },
5816                 (cap) -> {
5817                     assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID));
5818                     assertFalse(cap.hasCapability(NetworkCapabilities
5819                             .NET_CAPABILITY_NOT_RESTRICTED));
5820                 });
5821     }
5822     @Test
testNotOemPaidNetworkCapability()5823     public void testNotOemPaidNetworkCapability() throws Exception {
5824         // oemPaid introduced in S, not applicable to R
5825         assumeTrue(SdkLevel.isAtLeastS());
5826         mConnectedNetwork.oemPaid = false;
5827         connect();
5828         expectRegisterNetworkAgent((agentConfig) -> { },
5829                 (cap) -> {
5830                     assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID));
5831                     assertTrue(cap.hasCapability(NetworkCapabilities
5832                             .NET_CAPABILITY_NOT_RESTRICTED));
5833                 });
5834     }
5835 
5836     @Test
testOemPrivateNetworkCapability()5837     public void testOemPrivateNetworkCapability() throws Exception {
5838         // oemPrivate introduced in S, not applicable to R
5839         assumeTrue(SdkLevel.isAtLeastS());
5840         mConnectedNetwork.oemPrivate = true;
5841         connect();
5842         expectRegisterNetworkAgent((agentConfig) -> { },
5843                 (cap) -> {
5844                     assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE));
5845                     assertFalse(cap.hasCapability(NetworkCapabilities
5846                             .NET_CAPABILITY_NOT_RESTRICTED));
5847                 });
5848     }
5849 
5850     @Test
testNotOemPrivateNetworkCapability()5851     public void testNotOemPrivateNetworkCapability() throws Exception {
5852         // oemPrivate introduced in S, not applicable to R
5853         assumeTrue(SdkLevel.isAtLeastS());
5854         mConnectedNetwork.oemPrivate = false;
5855         connect();
5856         expectRegisterNetworkAgent((agentConfig) -> { },
5857                 (cap) -> {
5858                     assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE));
5859                     assertTrue(cap.hasCapability(NetworkCapabilities
5860                             .NET_CAPABILITY_NOT_RESTRICTED));
5861                 });
5862     }
5863 
5864     @Test
testSendLinkProbeFailure()5865     public void testSendLinkProbeFailure() throws Exception {
5866         mCmi.probeLink(mLinkProbeCallback, -1);
5867 
5868         verify(mLinkProbeCallback).onFailure(LinkProbeCallback.LINK_PROBE_ERROR_NOT_CONNECTED);
5869         verify(mLinkProbeCallback, never()).onAck(anyInt());
5870         verify(mWifiNative, never()).probeLink(any(), any(), any(), anyInt());
5871     }
5872 
5873     @Test
testSendLinkProbeSuccess()5874     public void testSendLinkProbeSuccess() throws Exception {
5875         connect();
5876 
5877         mCmi.probeLink(mLinkProbeCallback, -1);
5878 
5879         verify(mWifiNative).probeLink(any(), any(), eq(mLinkProbeCallback), eq(-1));
5880         verify(mLinkProbeCallback, never()).onFailure(anyInt());
5881         verify(mLinkProbeCallback, never()).onAck(anyInt());
5882     }
5883 
setupPasspointConnection()5884     private void setupPasspointConnection() throws Exception {
5885         mConnectedNetwork = spy(WifiConfigurationTestUtil.createPasspointNetwork());
5886         mConnectedNetwork.carrierId = CARRIER_ID_1;
5887         when(mWifiCarrierInfoManager.getBestMatchSubscriptionId(any(WifiConfiguration.class)))
5888                 .thenReturn(DATA_SUBID);
5889         when(mWifiCarrierInfoManager.isSimReady(DATA_SUBID)).thenReturn(true);
5890         mConnectedNetwork.enterpriseConfig.setAnonymousIdentity("");
5891         triggerConnect();
5892 
5893         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(mConnectedNetwork);
5894         when(mWifiConfigManager.getScanDetailCacheForNetwork(FRAMEWORK_NETWORK_ID))
5895                 .thenReturn(mScanDetailCache);
5896         when(mScanRequestProxy.getScanResult(TEST_BSSID_STR)).thenReturn(
5897                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
5898         when(mScanDetailCache.getScanDetail(TEST_BSSID_STR)).thenReturn(
5899                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq));
5900         when(mScanDetailCache.getScanResult(TEST_BSSID_STR)).thenReturn(
5901                 getGoogleGuestScanDetail(TEST_RSSI, TEST_BSSID_STR, sFreq).getScanResult());
5902 
5903         WifiSsid wifiSsid = WifiSsid.createFromByteArray(
5904                 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(mConnectedNetwork.SSID)));
5905         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
5906                 new NetworkConnectionEventInfo(0, wifiSsid, TEST_BSSID_STR, false));
5907         mLooper.dispatchAll();
5908         assertEquals("L3ProvisioningState", getCurrentState().getName());
5909     }
5910 
5911     /**
5912      * When connecting to a Passpoint network, verify that the Venue URL ANQP request is sent.
5913      */
5914     @Test
testVenueUrlRequestForPasspointNetworks()5915     public void testVenueUrlRequestForPasspointNetworks() throws Exception {
5916         setupPasspointConnection();
5917         verify(mPasspointManager).requestVenueUrlAnqpElement(any(ScanResult.class));
5918         assertEquals("L3ProvisioningState", getCurrentState().getName());
5919     }
5920 
5921     /**
5922      * Verify that the Venue URL ANQP request is not sent for non-Passpoint EAP networks
5923      */
5924     @Test
testVenueUrlNotRequestedForNonPasspointNetworks()5925     public void testVenueUrlNotRequestedForNonPasspointNetworks() throws Exception {
5926         setupEapSimConnection();
5927         verify(mPasspointManager, never()).requestVenueUrlAnqpElement(any(ScanResult.class));
5928         assertEquals("L3ProvisioningState", getCurrentState().getName());
5929     }
5930 
5931     @Test
testFirmwareRoam()5932     public void testFirmwareRoam() throws Exception {
5933         connect();
5934 
5935         // Now send a network connection (indicating a roam) event
5936         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT,
5937                 new NetworkConnectionEventInfo(0, TEST_WIFI_SSID, TEST_BSSID_STR1, false));
5938         mLooper.dispatchAll();
5939 
5940         verify(mContext, times(2)).sendStickyBroadcastAsUser(
5941                 argThat(new NetworkStateChangedIntentMatcher(CONNECTED)), any());
5942     }
5943 
5944     @Test
testProvisioningUpdateAfterConnect()5945     public void testProvisioningUpdateAfterConnect() throws Exception {
5946         connect();
5947 
5948         // Trigger a IP params update (maybe a dhcp lease renewal).
5949         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
5950         dhcpResults.baseConfiguration = new StaticIpConfiguration();
5951         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
5952         dhcpResults.baseConfiguration.ipAddress =
5953                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
5954         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
5955         dhcpResults.leaseDuration = 3600;
5956 
5957         injectDhcpSuccess(dhcpResults);
5958         mLooper.dispatchAll();
5959 
5960         verify(mContext, times(2)).sendStickyBroadcastAsUser(
5961                 argThat(new NetworkStateChangedIntentMatcher(CONNECTED)), any());
5962     }
5963 
5964     /**
5965      * Verify that the Deauth-Imminent WNM-Notification is handled by relaying to the Passpoint
5966      * Manager.
5967      */
5968     @Test
testHandlePasspointDeauthImminentWnmNotification()5969     public void testHandlePasspointDeauthImminentWnmNotification() throws Exception {
5970         setupEapSimConnection();
5971         WnmData wnmData = WnmData.createDeauthImminentEvent(TEST_BSSID, "", false,
5972                 TEST_DELAY_IN_SECONDS);
5973         mCmi.sendMessage(WifiMonitor.HS20_DEAUTH_IMMINENT_EVENT, 0, 0, wnmData);
5974         mLooper.dispatchAll();
5975         verify(mPasspointManager).handleDeauthImminentEvent(eq(wnmData),
5976                 any(WifiConfiguration.class));
5977     }
5978 
5979     /**
5980      * Verify that the network selection status will be updated and the function onEapFailure()
5981      * in EapFailureNotifier is called when a EAP Authentication failure is detected
5982      * with carrier erroe code.
5983      */
5984     @Test
testCarrierEapFailure()5985     public void testCarrierEapFailure() throws Exception {
5986         initializeAndAddNetworkAndVerifySuccess();
5987 
5988         startConnectSuccess();
5989 
5990         WifiConfiguration config = new WifiConfiguration();
5991         config.SSID = TEST_SSID;
5992         config.getNetworkSelectionStatus().setHasEverConnected(true);
5993         config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
5994         when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config);
5995         when(mEapFailureNotifier.onEapFailure(anyInt(), eq(config), anyBoolean())).thenReturn(true);
5996 
5997         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
5998                 WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE,
5999                 DEFINED_ERROR_CODE
6000         );
6001         mLooper.dispatchAll();
6002 
6003         verify(mEapFailureNotifier).onEapFailure(DEFINED_ERROR_CODE, config, true);
6004         verify(mWifiBlocklistMonitor).loadCarrierConfigsForDisableReasonInfos();
6005         verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
6006                 eq(WifiConfiguration.NetworkSelectionStatus
6007                         .DISABLED_AUTHENTICATION_PRIVATE_EAP_ERROR));
6008     }
6009 
6010     /**
6011      * When connected to a Passpoint network, verify that the Venue URL and T&C URL are updated in
6012      * the {@link LinkProperties} object when provisioning complete and when link properties change
6013      * events are received.
6014      */
6015     @Test
testVenueAndTCUrlsUpdateForPasspointNetworks()6016     public void testVenueAndTCUrlsUpdateForPasspointNetworks() throws Exception {
6017         // This tests new S functionality/APIs, not applicable to R.
6018         assumeTrue(SdkLevel.isAtLeastS());
6019         setupPasspointConnection();
6020         when(mPasspointManager.getVenueUrl(any(ScanResult.class))).thenReturn(new URL(VENUE_URL));
6021         WnmData wnmData = WnmData.createTermsAndConditionsAccetanceRequiredEvent(TEST_BSSID,
6022                 TEST_TERMS_AND_CONDITIONS_URL);
6023         when(mPasspointManager.handleTermsAndConditionsEvent(eq(wnmData),
6024                 any(WifiConfiguration.class))).thenReturn(new URL(TEST_TERMS_AND_CONDITIONS_URL));
6025         mCmi.sendMessage(WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT,
6026                 0, 0, wnmData);
6027         DhcpResultsParcelable dhcpResults = new DhcpResultsParcelable();
6028         dhcpResults.baseConfiguration = new StaticIpConfiguration();
6029         dhcpResults.baseConfiguration.gateway = InetAddresses.parseNumericAddress("1.2.3.4");
6030         dhcpResults.baseConfiguration.ipAddress =
6031                 new LinkAddress(InetAddresses.parseNumericAddress("192.168.1.100"), 0);
6032         dhcpResults.baseConfiguration.dnsServers.add(InetAddresses.parseNumericAddress("8.8.8.8"));
6033         dhcpResults.leaseDuration = 3600;
6034         injectDhcpSuccess(dhcpResults);
6035         mCmi.mNetworkAgent = null;
6036         mLooper.dispatchAll();
6037         LinkProperties linkProperties = mock(LinkProperties.class);
6038         mIpClientCallback.onLinkPropertiesChange(linkProperties);
6039         mLooper.dispatchAll();
6040         verify(mPasspointManager, times(2)).getVenueUrl(any(ScanResult.class));
6041         final ArgumentCaptor<CaptivePortalData> captivePortalDataCaptor =
6042                 ArgumentCaptor.forClass(CaptivePortalData.class);
6043         verify(linkProperties).setCaptivePortalData(captivePortalDataCaptor.capture());
6044         assertEquals(WifiConfigurationTestUtil.TEST_PROVIDER_FRIENDLY_NAME,
6045                 captivePortalDataCaptor.getValue().getVenueFriendlyName());
6046         assertEquals(VENUE_URL, captivePortalDataCaptor.getValue().getVenueInfoUrl().toString());
6047         assertEquals(TEST_TERMS_AND_CONDITIONS_URL, captivePortalDataCaptor.getValue()
6048                 .getUserPortalUrl().toString());
6049     }
6050 
6051     /**
6052      * Verify that the T&C WNM-Notification is handled by relaying to the Passpoint
6053      * Manager.
6054      */
6055     @Test
testHandlePasspointTermsAndConditionsWnmNotification()6056     public void testHandlePasspointTermsAndConditionsWnmNotification() throws Exception {
6057         setupEapSimConnection();
6058         WnmData wnmData = WnmData.createTermsAndConditionsAccetanceRequiredEvent(TEST_BSSID,
6059                 TEST_TERMS_AND_CONDITIONS_URL);
6060         when(mPasspointManager.handleTermsAndConditionsEvent(eq(wnmData),
6061                 any(WifiConfiguration.class))).thenReturn(new URL(TEST_TERMS_AND_CONDITIONS_URL));
6062         mCmi.sendMessage(WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT,
6063                 0, 0, wnmData);
6064         mLooper.dispatchAll();
6065         verify(mPasspointManager).handleTermsAndConditionsEvent(eq(wnmData),
6066                 any(WifiConfiguration.class));
6067         verify(mWifiNative, never()).disconnect(anyString());
6068     }
6069 
6070     /**
6071      * Verify that when a bad URL is received in the T&C WNM-Notification, the connection is
6072      * disconnected.
6073      */
6074     @Test
testHandlePasspointTermsAndConditionsWnmNotificationWithBadUrl()6075     public void testHandlePasspointTermsAndConditionsWnmNotificationWithBadUrl() throws Exception {
6076         setupEapSimConnection();
6077         WnmData wnmData = WnmData.createTermsAndConditionsAccetanceRequiredEvent(TEST_BSSID,
6078                 TEST_TERMS_AND_CONDITIONS_URL);
6079         when(mPasspointManager.handleTermsAndConditionsEvent(eq(wnmData),
6080                 any(WifiConfiguration.class))).thenReturn(null);
6081         mCmi.sendMessage(WifiMonitor.HS20_TERMS_AND_CONDITIONS_ACCEPTANCE_REQUIRED_EVENT,
6082                 0, 0, wnmData);
6083         mLooper.dispatchAll();
6084         verify(mPasspointManager).handleTermsAndConditionsEvent(eq(wnmData),
6085                 any(WifiConfiguration.class));
6086         verify(mWifiNative).disconnect(eq(WIFI_IFACE_NAME));
6087         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
6088                 eq(StaEvent.DISCONNECT_PASSPOINT_TAC));
6089     }
6090 
6091     /**
6092      * Verify that the Transition Disable event is routed correctly.
6093      */
6094     @Test
testTransitionDisableEvent()6095     public void testTransitionDisableEvent() throws Exception {
6096         final int networkId = FRAMEWORK_NETWORK_ID;
6097         final int indication = WifiMonitor.TDI_USE_WPA3_PERSONAL
6098                 | WifiMonitor.TDI_USE_WPA3_ENTERPRISE;
6099 
6100         initializeAndAddNetworkAndVerifySuccess();
6101 
6102         startConnectSuccess();
6103 
6104         mCmi.sendMessage(WifiMonitor.TRANSITION_DISABLE_INDICATION,
6105                 networkId, indication);
6106         mLooper.dispatchAll();
6107 
6108         verify(mWifiConfigManager).updateNetworkTransitionDisable(
6109                 eq(networkId), eq(indication));
6110     }
6111 
6112     /**
6113      * Verify that the network selection status will be updated with DISABLED_NETWORK_NOT_FOUND
6114      * when number of NETWORK_NOT_FOUND_EVENT event reaches the threshold.
6115      */
6116     @Test
testNetworkNotFoundEventUpdatesAssociationFailureStatus()6117     public void testNetworkNotFoundEventUpdatesAssociationFailureStatus()
6118             throws Exception {
6119         assumeTrue(SdkLevel.isAtLeastS());
6120         initializeAndAddNetworkAndVerifySuccess();
6121         mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
6122         for (int i = 0; i < ClientModeImpl.NETWORK_NOT_FOUND_EVENT_THRESHOLD; i++) {
6123             mCmi.sendMessage(WifiMonitor.NETWORK_NOT_FOUND_EVENT, DEFAULT_TEST_SSID);
6124         }
6125         mLooper.dispatchAll();
6126         verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(),
6127                 eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_NETWORK_NOT_FOUND));
6128         verify(mWifiConfigManager).setRecentFailureAssociationStatus(anyInt(),
6129                 eq(WifiConfiguration.RECENT_FAILURE_NETWORK_NOT_FOUND));
6130 
6131         verify(mWifiDiagnostics).reportConnectionEvent(
6132                 eq(WifiDiagnostics.CONNECTION_EVENT_FAILED), any());
6133         verify(mWifiConnectivityManager).handleConnectionAttemptEnded(
6134                 mClientModeManager,
6135                 WifiMetrics.ConnectionEvent.FAILURE_NETWORK_NOT_FOUND, TEST_BSSID_STR, TEST_SSID);
6136         verify(mWifiNetworkFactory).handleConnectionAttemptEnded(
6137                 eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_NOT_FOUND),
6138                 any(WifiConfiguration.class), eq(TEST_BSSID_STR));
6139         verify(mWifiNetworkSuggestionsManager).handleConnectionAttemptEnded(
6140                 eq(WifiMetrics.ConnectionEvent.FAILURE_NETWORK_NOT_FOUND),
6141                 any(WifiConfiguration.class), eq(null));
6142         verify(mWifiMetrics, never())
6143                 .incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
6144         verifyConnectionEventTimeoutDoesNotOccur();
6145 
6146         clearInvocations(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
6147                 mWifiNetworkSuggestionsManager);
6148 
6149         // Now trigger a disconnect event from supplicant, this should be ignored since the
6150         // connection tracking should have already ended.
6151         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT,
6152                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false));
6153         mLooper.dispatchAll();
6154 
6155         verifyNoMoreInteractions(mWifiDiagnostics, mWifiConfigManager, mWifiNetworkFactory,
6156                 mWifiNetworkSuggestionsManager);
6157     }
6158 
6159     /**
6160      * Verify that the subscriberId will be filled in NetworkAgentConfig
6161      * after connecting to a merged network. And also VCN policy will be checked.
6162      */
6163     @Test
triggerConnectToMergedNetwork()6164     public void triggerConnectToMergedNetwork() throws Exception {
6165         assumeTrue(SdkLevel.isAtLeastS());
6166         VcnManager vcnManager = mock(VcnManager.class);
6167         VcnNetworkPolicyResult vcnUnderlyingNetworkPolicy = mock(VcnNetworkPolicyResult.class);
6168         when(mContext.getSystemService(VcnManager.class)).thenReturn(vcnManager);
6169         ArgumentCaptor<VcnManager.VcnNetworkPolicyChangeListener> policyChangeListenerCaptor =
6170                 ArgumentCaptor.forClass(VcnManager.VcnNetworkPolicyChangeListener.class);
6171         InOrder inOrder = inOrder(vcnManager, vcnUnderlyingNetworkPolicy);
6172         doAnswer(new AnswerWithArguments() {
6173             public VcnNetworkPolicyResult answer(NetworkCapabilities networkCapabilities,
6174                     LinkProperties linkProperties) throws Exception {
6175                 networkCapabilities.removeCapability(
6176                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
6177                 when(vcnUnderlyingNetworkPolicy.getNetworkCapabilities())
6178                         .thenReturn(networkCapabilities);
6179                 return vcnUnderlyingNetworkPolicy;
6180             }
6181         }).when(vcnManager).applyVcnNetworkPolicy(any(), any());
6182         when(vcnUnderlyingNetworkPolicy.isTeardownRequested()).thenReturn(false);
6183 
6184         String testSubscriberId = "TestSubscriberId";
6185         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager);
6186         when(mDataTelephonyManager.getSubscriberId()).thenReturn(testSubscriberId);
6187         mConnectedNetwork.carrierMerged = true;
6188         mConnectedNetwork.subscriptionId = DATA_SUBID;
6189         connect();
6190         expectRegisterNetworkAgent((agentConfig) -> {
6191             assertEquals(testSubscriberId, agentConfig.subscriberId);
6192         }, (cap) -> {
6193                 assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
6194                 assertEquals(Collections.singleton(DATA_SUBID), cap.getSubscriptionIds());
6195             });
6196         // Verify VCN policy listener is registered
6197         inOrder.verify(vcnManager).addVcnNetworkPolicyChangeListener(any(),
6198                     policyChangeListenerCaptor.capture());
6199         assertNotNull(policyChangeListenerCaptor.getValue());
6200 
6201         // Verify getting new capability from VcnManager
6202         inOrder.verify(vcnManager).applyVcnNetworkPolicy(any(NetworkCapabilities.class),
6203                 any(LinkProperties.class));
6204         inOrder.verify(vcnUnderlyingNetworkPolicy).isTeardownRequested();
6205         inOrder.verify(vcnUnderlyingNetworkPolicy).getNetworkCapabilities();
6206 
6207         // Update policy with tear down request.
6208         when(vcnUnderlyingNetworkPolicy.isTeardownRequested()).thenReturn(true);
6209         policyChangeListenerCaptor.getValue().onPolicyChanged();
6210         mLooper.dispatchAll();
6211 
6212         // The merged carrier network should be disconnected.
6213         inOrder.verify(vcnManager).applyVcnNetworkPolicy(any(NetworkCapabilities.class),
6214                 any(LinkProperties.class));
6215         inOrder.verify(vcnUnderlyingNetworkPolicy).isTeardownRequested();
6216         inOrder.verify(vcnUnderlyingNetworkPolicy).getNetworkCapabilities();
6217         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
6218         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
6219                 eq(StaEvent.DISCONNECT_VCN_REQUEST));
6220         DisconnectEventInfo disconnectEventInfo =
6221                 new DisconnectEventInfo(TEST_SSID, TEST_BSSID_STR, 0, false);
6222         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, disconnectEventInfo);
6223         mLooper.dispatchAll();
6224         assertEquals("DisconnectedState", getCurrentState().getName());
6225 
6226         // In DisconnectedState, policy update should result no capability update.
6227         reset(mWifiConfigManager, vcnManager);
6228         policyChangeListenerCaptor.getValue().onPolicyChanged();
6229         verifyNoMoreInteractions(mWifiConfigManager, vcnManager);
6230     }
6231 
6232     /**
6233      * Verify when connect to a unmerged network, will not mark it as a VCN network.
6234      */
6235     @Test
triggerConnectToUnmergedNetwork()6236     public void triggerConnectToUnmergedNetwork() throws Exception {
6237         assumeTrue(SdkLevel.isAtLeastS());
6238         VcnManager vcnManager = mock(VcnManager.class);
6239         when(mContext.getSystemService(VcnManager.class)).thenReturn(vcnManager);
6240         VcnNetworkPolicyResult vcnUnderlyingNetworkPolicy = mock(VcnNetworkPolicyResult.class);
6241         ArgumentCaptor<VcnManager.VcnNetworkPolicyChangeListener> policyChangeListenerCaptor =
6242                 ArgumentCaptor.forClass(VcnManager.VcnNetworkPolicyChangeListener.class);
6243         doAnswer(new AnswerWithArguments() {
6244             public VcnNetworkPolicyResult answer(NetworkCapabilities networkCapabilities,
6245                     LinkProperties linkProperties) throws Exception {
6246                 networkCapabilities.removeCapability(
6247                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
6248                 when(vcnUnderlyingNetworkPolicy.getNetworkCapabilities())
6249                         .thenReturn(networkCapabilities);
6250                 return vcnUnderlyingNetworkPolicy;
6251             }
6252         }).when(vcnManager).applyVcnNetworkPolicy(any(), any());
6253         when(vcnUnderlyingNetworkPolicy.isTeardownRequested()).thenReturn(false);
6254 
6255         String testSubscriberId = "TestSubscriberId";
6256         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager);
6257         when(mDataTelephonyManager.getSubscriberId()).thenReturn(testSubscriberId);
6258         connect();
6259         expectRegisterNetworkAgent((agentConfig) -> {
6260             assertEquals(null, agentConfig.subscriberId);
6261         }, (cap) -> {
6262                 assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
6263                 assertTrue(cap.getSubscriptionIds().isEmpty());
6264             });
6265 
6266         // Verify VCN policy listener is registered
6267         verify(vcnManager, atLeastOnce()).addVcnNetworkPolicyChangeListener(any(),
6268                 policyChangeListenerCaptor.capture());
6269         assertNotNull(policyChangeListenerCaptor.getValue());
6270 
6271         policyChangeListenerCaptor.getValue().onPolicyChanged();
6272         mLooper.dispatchAll();
6273 
6274         verifyNoMoreInteractions(vcnManager, vcnUnderlyingNetworkPolicy);
6275     }
6276 
6277     /**
6278      * Verifies that we trigger a disconnect when the {@link WifiConfigManager}.
6279      * OnNetworkUpdateListener#onNetworkRemoved(WifiConfiguration)} is invoked.
6280      */
6281     @Test
testOnCarrierOffloadDisabled()6282     public void testOnCarrierOffloadDisabled() throws Exception {
6283         mConnectedNetwork.subscriptionId = DATA_SUBID;
6284         connect();
6285 
6286         mOffloadDisabledListenerArgumentCaptor.getValue()
6287                 .onCarrierOffloadDisabled(DATA_SUBID, false);
6288         mLooper.dispatchAll();
6289 
6290         verify(mWifiNative).disconnect(WIFI_IFACE_NAME);
6291         verify(mWifiMetrics).logStaEvent(anyString(), eq(StaEvent.TYPE_FRAMEWORK_DISCONNECT),
6292                 eq(StaEvent.DISCONNECT_CARRIER_OFFLOAD_DISABLED));
6293     }
6294 
6295     @Test
testPacketFilter()6296     public void testPacketFilter() throws Exception {
6297         connect();
6298 
6299         byte[] filter = new byte[20];
6300         new Random().nextBytes(filter);
6301         mIpClientCallback.installPacketFilter(filter);
6302         mLooper.dispatchAll();
6303 
6304         verify(mWifiNative).installPacketFilter(WIFI_IFACE_NAME, filter);
6305 
6306         when(mWifiNative.readPacketFilter(WIFI_IFACE_NAME)).thenReturn(filter);
6307         mIpClientCallback.startReadPacketFilter();
6308         mLooper.dispatchAll();
6309         verify(mIpClient).readPacketFilterComplete(filter);
6310         verify(mWifiNative).readPacketFilter(WIFI_IFACE_NAME);
6311     }
6312 
6313     @Test
testPacketFilterOnRoleChangeOnSecondaryCmm()6314     public void testPacketFilterOnRoleChangeOnSecondaryCmm() throws Exception {
6315         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6316         connect();
6317 
6318         verify(mWifiScoreReport).onRoleChanged(ROLE_CLIENT_PRIMARY);
6319 
6320         byte[] filter = new byte[20];
6321         new Random().nextBytes(filter);
6322         mIpClientCallback.installPacketFilter(filter);
6323         mLooper.dispatchAll();
6324 
6325         // just cache the data.
6326         verify(mWifiNative, never()).installPacketFilter(WIFI_IFACE_NAME, filter);
6327 
6328         when(mWifiNative.readPacketFilter(WIFI_IFACE_NAME)).thenReturn(filter);
6329         mIpClientCallback.startReadPacketFilter();
6330         mLooper.dispatchAll();
6331         verify(mIpClient).readPacketFilterComplete(filter);
6332         // return the cached the data.
6333         verify(mWifiNative, never()).readPacketFilter(WIFI_IFACE_NAME);
6334 
6335         // Now invoke role change, that should apply the APF
6336         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
6337         mCmi.onRoleChanged();
6338         verify(mWifiNative).installPacketFilter(WIFI_IFACE_NAME, filter);
6339         verify(mWifiScoreReport, times(2)).onRoleChanged(ROLE_CLIENT_PRIMARY);
6340     }
6341 
6342 
6343     @Test
testPacketFilterOnRoleChangeOnSecondaryCmmWithSupportForNonPrimaryApf()6344     public void testPacketFilterOnRoleChangeOnSecondaryCmmWithSupportForNonPrimaryApf()
6345             throws Exception {
6346         mResources.setBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta, true);
6347         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6348         connect();
6349 
6350         byte[] filter = new byte[20];
6351         new Random().nextBytes(filter);
6352         mIpClientCallback.installPacketFilter(filter);
6353         mLooper.dispatchAll();
6354 
6355         // apply the data.
6356         verify(mWifiNative).installPacketFilter(WIFI_IFACE_NAME, filter);
6357 
6358         when(mWifiNative.readPacketFilter(WIFI_IFACE_NAME)).thenReturn(filter);
6359         mIpClientCallback.startReadPacketFilter();
6360         mLooper.dispatchAll();
6361         verify(mIpClient).readPacketFilterComplete(filter);
6362         // return the applied data.
6363         verify(mWifiNative).readPacketFilter(WIFI_IFACE_NAME);
6364 
6365         // Now invoke role change, that should not apply the APF
6366         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
6367         mCmi.onRoleChanged();
6368         // ignore (since it was already applied)
6369         verify(mWifiNative, times(1)).installPacketFilter(WIFI_IFACE_NAME, filter);
6370     }
6371 
6372     @Test
testWifiInfoUpdateOnRoleChange()6373     public void testWifiInfoUpdateOnRoleChange() throws Exception {
6374         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6375         connect();
6376         // Should not set WifiInfo.isPrimary
6377         expectRegisterNetworkAgent((config) -> { }, (cap) -> {
6378             if (SdkLevel.isAtLeastS()) {
6379                 WifiInfo wifiInfoFromTi = (WifiInfo) cap.getTransportInfo();
6380                 assertFalse(wifiInfoFromTi.isPrimary());
6381             }
6382         });
6383         reset(mWifiNetworkAgent);
6384 
6385         // Now invoke role change, that should set WifiInfo.isPrimary
6386         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
6387         mCmi.onRoleChanged();
6388         expectNetworkAgentUpdateCapabilities((cap) -> {
6389             if (SdkLevel.isAtLeastS()) {
6390                 WifiInfo wifiInfoFromTi = (WifiInfo) cap.getTransportInfo();
6391                 assertTrue(wifiInfoFromTi.isPrimary());
6392             }
6393         });
6394     }
6395 
6396     /**
6397      * Verify onCellularConnectivityChanged plumbs the information to the right locations.
6398      */
6399     @Test
testOnCellularConnectivityChanged()6400     public void testOnCellularConnectivityChanged() {
6401         mCmi.onCellularConnectivityChanged(WifiDataStall.CELLULAR_DATA_AVAILABLE);
6402         verify(mWifiConfigManager).onCellularConnectivityChanged(
6403                 WifiDataStall.CELLULAR_DATA_AVAILABLE);
6404 
6405         mCmi.onCellularConnectivityChanged(WifiDataStall.CELLULAR_DATA_NOT_AVAILABLE);
6406         verify(mWifiConfigManager).onCellularConnectivityChanged(
6407                 WifiDataStall.CELLULAR_DATA_NOT_AVAILABLE);
6408     }
6409 
6410     /**
6411      * Verify that when cellular data is lost and wifi is not connected, we force a connectivity
6412      * scan.
6413      */
6414     @Test
testOnCellularConnectivityChangedForceConnectivityScan()6415     public void testOnCellularConnectivityChangedForceConnectivityScan() throws Exception {
6416         mResources.setBoolean(R.bool.config_wifiScanOnCellularDataLossEnabled, true);
6417         // verify a connectivity scan is forced since wifi is not connected
6418         mCmi.onCellularConnectivityChanged(WifiDataStall.CELLULAR_DATA_NOT_AVAILABLE);
6419         verify(mWifiConnectivityManager).forceConnectivityScan(WIFI_WORK_SOURCE);
6420 
6421         // verify that after wifi is connected, loss of cellular data will not trigger scans.
6422         connect();
6423         mCmi.onCellularConnectivityChanged(WifiDataStall.CELLULAR_DATA_NOT_AVAILABLE);
6424         verify(mWifiConnectivityManager).forceConnectivityScan(WIFI_WORK_SOURCE);
6425     }
6426 
setScreenState(boolean screenOn)6427     private void setScreenState(boolean screenOn) {
6428         BroadcastReceiver broadcastReceiver = mScreenStateBroadcastReceiverCaptor.getValue();
6429         assertNotNull(broadcastReceiver);
6430         Intent intent = new Intent(screenOn  ? ACTION_SCREEN_ON : ACTION_SCREEN_OFF);
6431         broadcastReceiver.onReceive(mContext, intent);
6432     }
6433 
6434     @Test
verifyRssiPollOnScreenStateChange()6435     public void verifyRssiPollOnScreenStateChange() throws Exception {
6436         setScreenState(true);
6437         connect();
6438         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6439 
6440         WifiLinkLayerStats oldLLStats = new WifiLinkLayerStats();
6441         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(oldLLStats);
6442         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6443         mLooper.dispatchAll();
6444         verify(mWifiNative).getWifiLinkLayerStats(WIFI_IFACE_NAME);
6445         verify(mWifiDataStall).checkDataStallAndThroughputSufficiency(WIFI_IFACE_NAME,
6446                 mConnectionCapabilities, null, oldLLStats, mWifiInfo);
6447         verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(WIFI_IFACE_NAME, oldLLStats);
6448 
6449         WifiLinkLayerStats newLLStats = new WifiLinkLayerStats();
6450         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(newLLStats);
6451         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6452         mLooper.dispatchAll();
6453         verify(mWifiNative, times(2)).getWifiLinkLayerStats(WIFI_IFACE_NAME);
6454 
6455         verify(mWifiDataStall).checkDataStallAndThroughputSufficiency(WIFI_IFACE_NAME,
6456                 mConnectionCapabilities, oldLLStats, newLLStats, mWifiInfo);
6457         verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(WIFI_IFACE_NAME, newLLStats);
6458 
6459         // Now set the screen state to false & move time forward, ensure no more link layer stats
6460         // collection.
6461         setScreenState(false);
6462         mLooper.dispatchAll();
6463         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6464 
6465         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6466         mLooper.dispatchAll();
6467 
6468         verifyNoMoreInteractions(mWifiNative, mWifiMetrics, mWifiDataStall);
6469     }
6470 
6471     @Test
verifyRssiPollOnSecondaryCmm()6472     public void verifyRssiPollOnSecondaryCmm() throws Exception {
6473         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6474         mCmi.onRoleChanged();
6475         setScreenState(true);
6476         connect();
6477         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6478 
6479         verifyNoMoreInteractions(mWifiNative, mWifiMetrics, mWifiDataStall);
6480 
6481         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(new WifiLinkLayerStats());
6482 
6483         // No link layer stats collection on secondary CMM.
6484         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6485         mLooper.dispatchAll();
6486 
6487         verifyNoMoreInteractions(mWifiNative, mWifiMetrics, mWifiDataStall);
6488     }
6489 
6490     @Test
verifyRssiPollOnOnRoleChangeToPrimary()6491     public void verifyRssiPollOnOnRoleChangeToPrimary() throws Exception {
6492         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6493         mCmi.onRoleChanged();
6494         setScreenState(true);
6495         connect();
6496         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6497 
6498         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(new WifiLinkLayerStats());
6499 
6500         // No link layer stats collection on secondary CMM.
6501         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6502         mLooper.dispatchAll();
6503 
6504         verifyNoMoreInteractions(mWifiNative, mWifiMetrics, mWifiDataStall);
6505 
6506         // Now invoke role change, that should start rssi polling on the new primary.
6507         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
6508         mCmi.onRoleChanged();
6509         mLooper.dispatchAll();
6510         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6511 
6512         WifiLinkLayerStats oldLLStats = new WifiLinkLayerStats();
6513         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(oldLLStats);
6514         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6515         mLooper.dispatchAll();
6516         verify(mWifiNative).getWifiLinkLayerStats(WIFI_IFACE_NAME);
6517         verify(mWifiDataStall).checkDataStallAndThroughputSufficiency(WIFI_IFACE_NAME,
6518                 mConnectionCapabilities, null, oldLLStats, mWifiInfo);
6519         verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(WIFI_IFACE_NAME, oldLLStats);
6520     }
6521 
6522     @Test
verifyRssiPollOnOnRoleChangeToSecondary()6523     public void verifyRssiPollOnOnRoleChangeToSecondary() throws Exception {
6524         setScreenState(true);
6525         connect();
6526         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6527 
6528         // RSSI polling is enabled on primary.
6529         WifiLinkLayerStats oldLLStats = new WifiLinkLayerStats();
6530         when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(oldLLStats);
6531         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6532         mLooper.dispatchAll();
6533         verify(mWifiNative).getWifiLinkLayerStats(WIFI_IFACE_NAME);
6534         verify(mWifiDataStall).checkDataStallAndThroughputSufficiency(WIFI_IFACE_NAME,
6535                 mConnectionCapabilities, null, oldLLStats, mWifiInfo);
6536         verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(WIFI_IFACE_NAME, oldLLStats);
6537 
6538         // Now invoke role change, that should stop rssi polling on the secondary.
6539         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
6540         mCmi.onRoleChanged();
6541         mLooper.dispatchAll();
6542         clearInvocations(mWifiNative, mWifiMetrics, mWifiDataStall);
6543 
6544         // No link layer stats collection on secondary CMM.
6545         mLooper.moveTimeForward(mWifiGlobals.getPollRssiIntervalMillis());
6546         mLooper.dispatchAll();
6547 
6548         verifyNoMoreInteractions(mWifiNative, mWifiMetrics, mWifiDataStall);
6549     }
6550 
6551     @Test
testClientModeImplWhenIpClientIsNotReady()6552     public void testClientModeImplWhenIpClientIsNotReady() throws Exception {
6553         WifiConfiguration config = mConnectedNetwork;
6554         config.networkId = FRAMEWORK_NETWORK_ID;
6555         config.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS);
6556         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
6557         config.getNetworkSelectionStatus().setHasEverConnected(mTestNetworkParams.hasEverConnected);
6558         assertNull(config.getNetworkSelectionStatus().getCandidateSecurityParams());
6559 
6560         mFrameworkFacade = mock(FrameworkFacade.class);
6561         ArgumentCaptor<IpClientCallbacks> captor = ArgumentCaptor.forClass(IpClientCallbacks.class);
6562         // reset mWifiNative since initializeCmi() was called in setup()
6563         resetWifiNative();
6564 
6565         // reinitialize ClientModeImpl with IpClient is not ready.
6566         initializeCmi();
6567         verify(mFrameworkFacade).makeIpClient(any(), anyString(), captor.capture());
6568 
6569         // Manually connect should fail.
6570         IActionListener connectActionListener = mock(IActionListener.class);
6571         mCmi.connectNetwork(
6572                 new NetworkUpdateResult(config.networkId),
6573                 new ActionListenerWrapper(connectActionListener),
6574                 Binder.getCallingUid());
6575         mLooper.dispatchAll();
6576         verify(connectActionListener).onFailure(WifiManager.ERROR);
6577         verify(mWifiConfigManager, never())
6578                 .getConfiguredNetworkWithoutMasking(eq(config.networkId));
6579         verify(mWifiNative, never()).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
6580 
6581         // Auto connect should also fail
6582         mCmi.startConnectToNetwork(config.networkId, MANAGED_PROFILE_UID, config.BSSID);
6583         mLooper.dispatchAll();
6584         verify(mWifiConfigManager, never())
6585                 .getConfiguredNetworkWithoutMasking(eq(config.networkId));
6586         verify(mWifiNative, never()).connectToNetwork(eq(WIFI_IFACE_NAME), eq(config));
6587 
6588         // Make IpClient ready connection should succeed.
6589         captor.getValue().onIpClientCreated(mIpClient);
6590         mLooper.dispatchAll();
6591 
6592         triggerConnect();
6593     }
6594 }
6595