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