1 /*
2  * Copyright (C) 2010 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.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT;
20 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY;
21 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256;
22 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384;
23 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
24 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
25 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
26 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
27 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
28 
29 import static com.android.server.wifi.WifiDataStall.INVALID_THROUGHPUT;
30 
31 import android.annotation.IntDef;
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 import android.app.ActivityManager;
35 import android.bluetooth.BluetoothAdapter;
36 import android.content.BroadcastReceiver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.content.pm.PackageManager;
41 import android.net.ConnectivityManager;
42 import android.net.DhcpResultsParcelable;
43 import android.net.InvalidPacketException;
44 import android.net.IpConfiguration;
45 import android.net.KeepalivePacketData;
46 import android.net.Layer2PacketParcelable;
47 import android.net.LinkProperties;
48 import android.net.MacAddress;
49 import android.net.MatchAllNetworkSpecifier;
50 import android.net.NattKeepalivePacketData;
51 import android.net.Network;
52 import android.net.NetworkAgent;
53 import android.net.NetworkAgentConfig;
54 import android.net.NetworkCapabilities;
55 import android.net.NetworkInfo;
56 import android.net.NetworkInfo.DetailedState;
57 import android.net.NetworkProvider;
58 import android.net.SocketKeepalive;
59 import android.net.StaticIpConfiguration;
60 import android.net.TcpKeepalivePacketData;
61 import android.net.Uri;
62 import android.net.ip.IIpClient;
63 import android.net.ip.IpClientCallbacks;
64 import android.net.ip.IpClientManager;
65 import android.net.shared.Layer2Information;
66 import android.net.shared.ProvisioningConfiguration;
67 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
68 import android.net.util.MacAddressUtils;
69 import android.net.util.NetUtils;
70 import android.net.wifi.IActionListener;
71 import android.net.wifi.INetworkRequestMatchCallback;
72 import android.net.wifi.ScanResult;
73 import android.net.wifi.SupplicantState;
74 import android.net.wifi.WifiAnnotations.WifiStandard;
75 import android.net.wifi.WifiConfiguration;
76 import android.net.wifi.WifiEnterpriseConfig;
77 import android.net.wifi.WifiInfo;
78 import android.net.wifi.WifiManager;
79 import android.net.wifi.WifiManager.DeviceMobilityState;
80 import android.net.wifi.WifiNetworkAgentSpecifier;
81 import android.net.wifi.WifiScanner;
82 import android.net.wifi.hotspot2.IProvisioningCallback;
83 import android.net.wifi.hotspot2.OsuProvider;
84 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
85 import android.net.wifi.nl80211.WifiNl80211Manager;
86 import android.net.wifi.p2p.WifiP2pManager;
87 import android.os.BatteryStatsManager;
88 import android.os.Bundle;
89 import android.os.ConditionVariable;
90 import android.os.IBinder;
91 import android.os.Looper;
92 import android.os.Message;
93 import android.os.Messenger;
94 import android.os.PowerManager;
95 import android.os.Process;
96 import android.os.RemoteException;
97 import android.os.UserHandle;
98 import android.os.UserManager;
99 import android.os.WorkSource;
100 import android.provider.Settings;
101 import android.system.OsConstants;
102 import android.telephony.SubscriptionManager;
103 import android.telephony.TelephonyManager;
104 import android.text.TextUtils;
105 import android.util.Log;
106 import android.util.Pair;
107 import android.util.SparseArray;
108 
109 import com.android.internal.annotations.VisibleForTesting;
110 import com.android.internal.util.AsyncChannel;
111 import com.android.internal.util.MessageUtils;
112 import com.android.internal.util.Protocol;
113 import com.android.internal.util.State;
114 import com.android.internal.util.StateMachine;
115 import com.android.net.module.util.Inet4AddressUtils;
116 import com.android.server.wifi.MboOceController.BtmFrameData;
117 import com.android.server.wifi.WifiCarrierInfoManager.SimAuthRequestData;
118 import com.android.server.wifi.WifiCarrierInfoManager.SimAuthResponseData;
119 import com.android.server.wifi.hotspot2.AnqpEvent;
120 import com.android.server.wifi.hotspot2.IconEvent;
121 import com.android.server.wifi.hotspot2.NetworkDetail;
122 import com.android.server.wifi.hotspot2.PasspointManager;
123 import com.android.server.wifi.hotspot2.WnmData;
124 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
125 import com.android.server.wifi.proto.WifiStatsLog;
126 import com.android.server.wifi.proto.nano.WifiMetricsProto;
127 import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent;
128 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent;
129 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats;
130 import com.android.server.wifi.util.ExternalCallbackTracker;
131 import com.android.server.wifi.util.NativeUtil;
132 import com.android.server.wifi.util.RssiUtil;
133 import com.android.server.wifi.util.ScanResultUtil;
134 import com.android.server.wifi.util.WifiPermissionsUtil;
135 import com.android.server.wifi.util.WifiPermissionsWrapper;
136 import com.android.wifi.resources.R;
137 
138 import java.io.BufferedReader;
139 import java.io.FileDescriptor;
140 import java.io.FileNotFoundException;
141 import java.io.FileReader;
142 import java.io.IOException;
143 import java.io.PrintWriter;
144 import java.lang.annotation.Retention;
145 import java.lang.annotation.RetentionPolicy;
146 import java.net.Inet4Address;
147 import java.net.Inet6Address;
148 import java.net.InetAddress;
149 import java.time.Duration;
150 import java.util.ArrayList;
151 import java.util.Arrays;
152 import java.util.List;
153 import java.util.Set;
154 import java.util.concurrent.atomic.AtomicBoolean;
155 import java.util.concurrent.atomic.AtomicInteger;
156 
157 /**
158  * Implementation of ClientMode.  Event handling for Client mode logic is done here,
159  * and all changes in connectivity state are initiated here.
160  *
161  * @hide
162  */
163 public class ClientModeImpl extends StateMachine {
164 
165     private static final String NETWORKTYPE = "WIFI";
166     @VisibleForTesting public static final short NUM_LOG_RECS_NORMAL = 100;
167     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE_LOW_MEMORY = 200;
168     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE = 3000;
169 
170     // Association rejection reason codes
171     @VisibleForTesting
172     protected static final int REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
173 
174     private static final String TAG = "WifiClientModeImpl";
175 
176     private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
177 
178     private static final String GOOGLE_OUI = "DA-A1-19";
179 
180     private static final String EXTRA_OSU_ICON_QUERY_BSSID = "BSSID";
181     private static final String EXTRA_OSU_ICON_QUERY_FILENAME = "FILENAME";
182     private static final String EXTRA_OSU_PROVIDER = "OsuProvider";
183     private static final String EXTRA_UID = "uid";
184     private static final String EXTRA_PACKAGE_NAME = "PackageName";
185     private static final String EXTRA_PASSPOINT_CONFIGURATION = "PasspointConfiguration";
186     private static final int IPCLIENT_STARTUP_TIMEOUT_MS = 20 * 60 * 1000; // 20 minutes!
187     private static final int IPCLIENT_SHUTDOWN_TIMEOUT_MS = 60_000; // 60 seconds
188 
189     private boolean mVerboseLoggingEnabled = false;
190     private final WifiPermissionsWrapper mWifiPermissionsWrapper;
191 
192     /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
193      * the corresponding BSSID.
194      */
195     private boolean mDidBlackListBSSID = false;
196 
197     /**
198      * Log with error attribute
199      *
200      * @param s is string log
201      */
202     @Override
loge(String s)203     protected void loge(String s) {
204         Log.e(getName(), s);
205     }
206     @Override
logd(String s)207     protected void logd(String s) {
208         Log.d(getName(), s);
209     }
210     @Override
log(String s)211     protected void log(String s) {
212         Log.d(getName(), s);
213     }
214     private final WifiMetrics mWifiMetrics;
215     private final WifiInjector mWifiInjector;
216     private final WifiMonitor mWifiMonitor;
217     private final WifiNative mWifiNative;
218     private final WifiPermissionsUtil mWifiPermissionsUtil;
219     private final WifiConfigManager mWifiConfigManager;
220     private final WifiConnectivityManager mWifiConnectivityManager;
221     private final BssidBlocklistMonitor mBssidBlocklistMonitor;
222     private ConnectivityManager mCm;
223     private BaseWifiDiagnostics mWifiDiagnostics;
224     private final boolean mP2pSupported;
225     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
226     private boolean mTemporarilyDisconnectWifi = false;
227     private final Clock mClock;
228     private final PropertyService mPropertyService;
229     private final BuildProperties mBuildProperties;
230     private final WifiCountryCode mCountryCode;
231     private final WifiScoreCard mWifiScoreCard;
232     private final WifiHealthMonitor mWifiHealthMonitor;
233     private final WifiScoreReport mWifiScoreReport;
234     private final SarManager mSarManager;
235     private final WifiTrafficPoller mWifiTrafficPoller;
getWifiScoreReport()236     public WifiScoreReport getWifiScoreReport() {
237         return mWifiScoreReport;
238     }
239     private final PasspointManager mPasspointManager;
240     private final WifiDataStall mWifiDataStall;
241     private final LinkProbeManager mLinkProbeManager;
242     private final MboOceController mMboOceController;
243 
244     private final McastLockManagerFilterController mMcastLockManagerFilterController;
245     private final ActivityManager mActivityManager;
246 
247     private boolean mScreenOn = false;
248 
249     private String mInterfaceName;
250 
251     private int mLastSignalLevel = -1;
252     private String mLastBssid;
253     private int mLastNetworkId; // The network Id we successfully joined
254     // The subId used by WifiConfiguration with SIM credential which was connected successfully
255     private int mLastSubId;
256     private String mLastSimBasedConnectionCarrierName;
257 
258     private boolean mIpReachabilityDisconnectEnabled = true;
259 
processRssiThreshold(byte curRssi, int reason, WifiNative.WifiRssiEventHandler rssiHandler)260     private void processRssiThreshold(byte curRssi, int reason,
261             WifiNative.WifiRssiEventHandler rssiHandler) {
262         if (curRssi == Byte.MAX_VALUE || curRssi == Byte.MIN_VALUE) {
263             Log.wtf(TAG, "processRssiThreshold: Invalid rssi " + curRssi);
264             return;
265         }
266         for (int i = 0; i < mRssiRanges.length; i++) {
267             if (curRssi < mRssiRanges[i]) {
268                 // Assume sorted values(ascending order) for rssi,
269                 // bounded by high(127) and low(-128) at extremeties
270                 byte maxRssi = mRssiRanges[i];
271                 byte minRssi = mRssiRanges[i - 1];
272                 // This value of hw has to be believed as this value is averaged and has breached
273                 // the rssi thresholds and raised event to host. This would be eggregious if this
274                 // value is invalid
275                 mWifiInfo.setRssi(curRssi);
276                 updateCapabilities();
277                 int ret = startRssiMonitoringOffload(maxRssi, minRssi, rssiHandler);
278                 Log.d(TAG, "Re-program RSSI thresholds for " + getWhatToString(reason)
279                         + ": [" + minRssi + ", " + maxRssi + "], curRssi=" + curRssi
280                         + " ret=" + ret);
281                 break;
282             }
283         }
284     }
285 
286     private boolean mEnableRssiPolling = false;
287     // Accessed via Binder thread ({get,set}PollRssiIntervalMsecs), and the main Wifi thread.
288     private volatile int mPollRssiIntervalMsecs = -1;
289     private int mRssiPollToken = 0;
290     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
291     * In CONNECT_MODE, the STA can scan and connect to an access point
292     * In SCAN_ONLY_MODE, the STA can only scan for access points
293     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
294     */
295     private int mOperationalMode = DISABLED_MODE;
296 
297     // variable indicating we are expecting a mode switch - do not attempt recovery for failures
298     private boolean mModeChange = false;
299 
300     private ClientModeManager.Listener mClientModeCallback = null;
301 
302     private boolean mBluetoothConnectionActive = false;
303 
304     private PowerManager.WakeLock mSuspendWakeLock;
305 
306     /**
307      * Maximum allowable interval in milliseconds between polling for RSSI and linkspeed
308      * information. This is also used as the polling interval for WifiTrafficPoller, which updates
309      * its data activity on every CMD_RSSI_POLL.
310      */
311     private static final int MAXIMUM_POLL_RSSI_INTERVAL_MSECS = 6000;
312 
313     /**
314      * Interval in milliseconds between receiving a disconnect event
315      * while connected to a good AP, and handling the disconnect proper
316      */
317     private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 4000;
318 
319     /**
320      * Delay between supplicant restarts upon failure to establish connection
321      */
322     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
323 
324     /**
325      * Number of times we attempt to restart supplicant
326      */
327     private static final int SUPPLICANT_RESTART_TRIES = 5;
328 
329     /**
330      * Value to set in wpa_supplicant "bssid" field when we don't want to restrict connection to
331      * a specific AP.
332      */
333     public static final String SUPPLICANT_BSSID_ANY = "any";
334 
335     /**
336      * The link properties of the wifi interface.
337      * Do not modify this directly; use updateLinkProperties instead.
338      */
339     private LinkProperties mLinkProperties;
340 
341     /* Tracks sequence number on a periodic scan message */
342     private int mPeriodicScanToken = 0;
343 
344     private Context mContext;
345 
346     private final Object mDhcpResultsParcelableLock = new Object();
347     @NonNull
348     private DhcpResultsParcelable mDhcpResultsParcelable = new DhcpResultsParcelable();
349 
350     // NOTE: Do not return to clients - see syncRequestConnectionInfo()
351     private final ExtendedWifiInfo mWifiInfo;
352     // TODO : remove this member. It should be possible to only call sendNetworkChangeBroadcast when
353     // the state actually changed, and to deduce the state of the agent from the state of the
354     // machine when generating the NetworkInfo for the broadcast.
355     private DetailedState mNetworkAgentState;
356     private SupplicantStateTracker mSupplicantStateTracker;
357 
358     // Indicates that framework is attempting to roam, set true on CMD_START_ROAM, set false when
359     // wifi connects or fails to connect
360     private boolean mIsAutoRoaming = false;
361 
362     // Roaming failure count
363     private int mRoamFailCount = 0;
364 
365     // This is the BSSID we are trying to associate to, it can be set to SUPPLICANT_BSSID_ANY
366     // if we havent selected a BSSID for joining.
367     private String mTargetBssid = SUPPLICANT_BSSID_ANY;
368     // This one is used to track the current target network ID. This is used for error
369     // handling during connection setup since many error message from supplicant does not report
370     // SSID. Once connected, it will be set to invalid
371     private int mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
372     private long mLastDriverRoamAttempt = 0;
373     private WifiConfiguration mTargetWifiConfiguration = null;
374 
getPollRssiIntervalMsecs()375     int getPollRssiIntervalMsecs() {
376         if (mPollRssiIntervalMsecs > 0) {
377             return mPollRssiIntervalMsecs;
378         }
379         return Math.min(mContext.getResources().getInteger(
380                 R.integer.config_wifiPollRssiIntervalMilliseconds),
381                         MAXIMUM_POLL_RSSI_INTERVAL_MSECS);
382     }
383 
setPollRssiIntervalMsecs(int newPollIntervalMsecs)384     void setPollRssiIntervalMsecs(int newPollIntervalMsecs) {
385         mPollRssiIntervalMsecs = newPollIntervalMsecs;
386     }
387 
388     /**
389      * Method to clear {@link #mTargetBssid} and reset the current connected network's
390      * bssid in wpa_supplicant after a roam/connect attempt.
391      */
clearTargetBssid(String dbg)392     public boolean clearTargetBssid(String dbg) {
393         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
394         if (config == null) {
395             return false;
396         }
397         String bssid = SUPPLICANT_BSSID_ANY;
398         if (config.BSSID != null) {
399             bssid = config.BSSID;
400             if (mVerboseLoggingEnabled) {
401                 Log.d(TAG, "force BSSID to " + bssid + "due to config");
402             }
403         }
404         if (mVerboseLoggingEnabled) {
405             logd(dbg + " clearTargetBssid " + bssid + " key=" + config.getKey());
406         }
407         mTargetBssid = bssid;
408         return mWifiNative.setConfiguredNetworkBSSID(mInterfaceName, bssid);
409     }
410 
411     /**
412      * Set Config's default BSSID (for association purpose) and {@link #mTargetBssid}
413      * @param config config need set BSSID
414      * @param bssid  default BSSID to assocaite with when connect to this network
415      * @return false -- does not change the current default BSSID of the configure
416      *         true -- change the  current default BSSID of the configur
417      */
setTargetBssid(WifiConfiguration config, String bssid)418     private boolean setTargetBssid(WifiConfiguration config, String bssid) {
419         if (config == null || bssid == null) {
420             return false;
421         }
422         if (config.BSSID != null) {
423             bssid = config.BSSID;
424             if (mVerboseLoggingEnabled) {
425                 Log.d(TAG, "force BSSID to " + bssid + "due to config");
426             }
427         }
428         if (mVerboseLoggingEnabled) {
429             Log.d(TAG, "setTargetBssid set to " + bssid + " key=" + config.getKey());
430         }
431         mTargetBssid = bssid;
432         config.getNetworkSelectionStatus().setNetworkSelectionBSSID(bssid);
433         return true;
434     }
435 
436     private volatile IpClientManager mIpClient;
437     private IpClientCallbacksImpl mIpClientCallbacks;
438 
439     // Channel for sending replies.
440     private AsyncChannel mReplyChannel = new AsyncChannel();
441 
442     // Used to initiate a connection with WifiP2pService
443     private AsyncChannel mWifiP2pChannel;
444 
445     private WifiNetworkFactory mNetworkFactory;
446     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
447     private WifiNetworkAgent mNetworkAgent;
448 
449     private byte[] mRssiRanges;
450 
451     // Used to filter out requests we couldn't possibly satisfy.
452     private final NetworkCapabilities mNetworkCapabilitiesFilter;
453 
454     private final ExternalCallbackTracker<IActionListener> mProcessingActionListeners;
455 
456     /* The base for wifi message types */
457     static final int BASE = Protocol.BASE_WIFI;
458     /* BT state change, e.g., on or off */
459     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE                 = BASE + 31;
460     /* BT connection state change, e.g., connected or disconnected */
461     static final int CMD_BLUETOOTH_ADAPTER_CONNECTION_STATE_CHANGE      = BASE + 32;
462 
463     /* Get adaptors */
464     static final int CMD_GET_SUPPORTED_FEATURES                         = BASE + 61;
465     /* Get Link Layer Stats thru HAL */
466     static final int CMD_GET_LINK_LAYER_STATS                           = BASE + 63;
467     /* Supplicant commands after driver start*/
468     /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
469     static final int CMD_SET_OPERATIONAL_MODE                           = BASE + 72;
470     /* Disconnect from a network */
471     static final int CMD_DISCONNECT                                     = BASE + 73;
472     /* Reconnect to a network */
473     static final int CMD_RECONNECT                                      = BASE + 74;
474     /* Reassociate to a network */
475     static final int CMD_REASSOCIATE                                    = BASE + 75;
476 
477     /* Controls suspend mode optimizations
478      *
479      * When high perf mode is enabled, suspend mode optimizations are disabled
480      *
481      * When high perf mode is disabled, suspend mode optimizations are enabled
482      *
483      * Suspend mode optimizations include:
484      * - packet filtering
485      * - turn off roaming
486      * - DTIM wake up settings
487      */
488     static final int CMD_SET_HIGH_PERF_MODE                             = BASE + 77;
489     /* Enables RSSI poll */
490     static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
491     /* RSSI poll */
492     static final int CMD_RSSI_POLL                                      = BASE + 83;
493     /** Runs RSSI poll once */
494     static final int CMD_ONESHOT_RSSI_POLL                              = BASE + 84;
495     /* Enable suspend mode optimizations in the driver */
496     static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
497 
498     /* Enable TDLS on a specific MAC address */
499     static final int CMD_ENABLE_TDLS                                    = BASE + 92;
500 
501     /**
502      * Watchdog for protecting against b/16823537
503      * Leave time for 4-way handshake to succeed
504      */
505     static final int ROAM_GUARD_TIMER_MSEC = 15000;
506 
507     int mRoamWatchdogCount = 0;
508     /* Roam state watchdog */
509     static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
510     /* Screen change intent handling */
511     static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
512 
513     /* Disconnecting state watchdog */
514     static final int CMD_DISCONNECTING_WATCHDOG_TIMER                   = BASE + 96;
515 
516     /* SIM is removed; reset any cached data for it */
517     static final int CMD_RESET_SIM_NETWORKS                             = BASE + 101;
518 
519     @Retention(RetentionPolicy.SOURCE)
520     @IntDef(prefix = {"RESET_SIM_REASON_"},
521             value = {
522                     RESET_SIM_REASON_SIM_REMOVED,
523                     RESET_SIM_REASON_SIM_INSERTED,
524                     RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED})
525     @interface ResetSimReason {}
526     static final int RESET_SIM_REASON_SIM_REMOVED              = 0;
527     static final int RESET_SIM_REASON_SIM_INSERTED             = 1;
528     static final int RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED = 2;
529 
530     /* OSU APIs */
531     static final int CMD_QUERY_OSU_ICON                                 = BASE + 104;
532 
533     /* Commands from/to the SupplicantStateTracker */
534     /* Reset the supplicant state tracker */
535     static final int CMD_RESET_SUPPLICANT_STATE                         = BASE + 111;
536 
537     int mDisconnectingWatchdogCount = 0;
538     static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
539 
540     /**
541      * Indicates the end of boot process, should be used to trigger load from config store,
542      * initiate connection attempt, etc.
543      * */
544     static final int CMD_BOOT_COMPLETED                                 = BASE + 134;
545     /**
546      * Initialize ClientModeImpl. This is currently used to initialize the
547      * {@link HalDeviceManager} module.
548      */
549     static final int CMD_INITIALIZE                                     = BASE + 135;
550 
551     /* We now have a valid IP configuration. */
552     static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
553     /* We no longer have a valid IP configuration. */
554     static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
555     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
556     static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
557 
558     static final int CMD_START_CONNECT                                  = BASE + 143;
559 
560     private static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
561     private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
562     private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
563 
564     static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
565 
566     static final int CMD_START_ROAM                                     = BASE + 145;
567 
568     static final int CMD_NETWORK_STATUS                                 = BASE + 148;
569 
570     /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
571     static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
572 
573     static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
574 
575     /* used to offload sending IP packet */
576     static final int CMD_START_IP_PACKET_OFFLOAD                        = BASE + 160;
577 
578     /* used to stop offload sending IP packet */
579     static final int CMD_STOP_IP_PACKET_OFFLOAD                         = BASE + 161;
580 
581     /* used to start rssi monitoring in hw */
582     static final int CMD_START_RSSI_MONITORING_OFFLOAD                  = BASE + 162;
583 
584     /* used to stop rssi moniroting in hw */
585     static final int CMD_STOP_RSSI_MONITORING_OFFLOAD                   = BASE + 163;
586 
587     /* used to indicated RSSI threshold breach in hw */
588     static final int CMD_RSSI_THRESHOLD_BREACHED                        = BASE + 164;
589 
590     /**
591      * Used to handle messages bounced between ClientModeImpl and IpClient.
592      */
593     static final int CMD_IPV4_PROVISIONING_SUCCESS                      = BASE + 200;
594     static final int CMD_IPV4_PROVISIONING_FAILURE                      = BASE + 201;
595 
596     /* Push a new APF program to the HAL */
597     static final int CMD_INSTALL_PACKET_FILTER                          = BASE + 202;
598 
599     /* Enable/disable fallback packet filtering */
600     static final int CMD_SET_FALLBACK_PACKET_FILTERING                  = BASE + 203;
601 
602     /* Enable/disable Neighbor Discovery offload functionality. */
603     static final int CMD_CONFIG_ND_OFFLOAD                              = BASE + 204;
604 
605     /* Read the APF program & data buffer */
606     static final int CMD_READ_PACKET_FILTER                             = BASE + 208;
607 
608     /** Used to add packet filter to apf. */
609     static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = BASE + 209;
610 
611     /** Used to remove packet filter from apf. */
612     static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = BASE + 210;
613 
614     /* Indicates that diagnostics should time out a connection start event. */
615     static final int CMD_DIAGS_CONNECT_TIMEOUT                          = BASE + 252;
616 
617     // Start subscription provisioning with a given provider
618     private static final int CMD_START_SUBSCRIPTION_PROVISIONING        = BASE + 254;
619 
620     @VisibleForTesting
621     static final int CMD_PRE_DHCP_ACTION                                = BASE + 255;
622     private static final int CMD_PRE_DHCP_ACTION_COMPLETE               = BASE + 256;
623     private static final int CMD_POST_DHCP_ACTION                       = BASE + 257;
624 
625     private static final int CMD_CONNECT_NETWORK                        = BASE + 258;
626     private static final int CMD_SAVE_NETWORK                           = BASE + 259;
627 
628     /* Start connection to FILS AP*/
629     static final int CMD_START_FILS_CONNECTION                          = BASE + 262;
630 
631     private static final int CMD_GET_CURRENT_NETWORK                    = BASE + 263;
632 
633     // For message logging.
634     private static final Class[] sMessageClasses = {
635             AsyncChannel.class, ClientModeImpl.class };
636     private static final SparseArray<String> sGetWhatToString =
637             MessageUtils.findMessageNames(sMessageClasses);
638 
639 
640     /* Wifi state machine modes of operation */
641     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
642     public static final int CONNECT_MODE = 1;
643     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
644     public static final int SCAN_ONLY_MODE = 2;
645     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
646     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
647     /* DISABLED_MODE - Don't connect, don't scan, don't be an AP */
648     public static final int DISABLED_MODE = 4;
649 
650     private static final int SUCCESS = 1;
651     private static final int FAILURE = -1;
652 
653     /* Tracks if suspend optimizations need to be disabled by DHCP,
654      * screen or due to high perf mode.
655      * When any of them needs to disable it, we keep the suspend optimizations
656      * disabled
657      */
658     private int mSuspendOptNeedsDisabled = 0;
659 
660     private static final int SUSPEND_DUE_TO_DHCP = 1;
661     private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
662     private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
663 
664     /**
665      * Time window in milliseconds for which we send
666      * {@link NetworkAgent#explicitlySelected(boolean, boolean)}
667      * after connecting to the network which the user last selected.
668      */
669     @VisibleForTesting
670     public static final int LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS = 30 * 1000;
671 
672     /* Tracks if user has enabled Connected Mac Randomization through settings */
673 
674     /**
675      * Supplicant scan interval in milliseconds.
676      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
677      * from the default config if the setting is not set
678      */
679     private long mSupplicantScanIntervalMs;
680 
681     int mRunningBeaconCount = 0;
682 
683     /* Default parent state */
684     private State mDefaultState = new DefaultState();
685     /* Connecting to an access point */
686     private State mConnectModeState = new ConnectModeState();
687     /* Connected at 802.11 (L2) level */
688     private State mL2ConnectedState = new L2ConnectedState();
689     /* fetching IP after connection to access point (assoc+auth complete) */
690     private State mObtainingIpState = new ObtainingIpState();
691     /* Connected with IP addr */
692     private State mConnectedState = new ConnectedState();
693     /* Roaming */
694     private State mRoamingState = new RoamingState();
695     /* disconnect issued, waiting for network disconnect confirmation */
696     private State mDisconnectingState = new DisconnectingState();
697     /* Network is not connected, supplicant assoc+auth is not complete */
698     private State mDisconnectedState = new DisconnectedState();
699 
700     /*
701      * FILS connection related variables.
702      */
703     /* To indicate to IpClient whether HLP IEs were included or not in assoc request */
704     private boolean mSentHLPs = false;
705     /* Tracks IpClient start state until (FILS_)NETWORK_CONNECTION_EVENT event */
706     private boolean mIpClientWithPreConnection = false;
707 
708     /**
709      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
710      * {@link WifiManager#WIFI_STATE_DISABLING},
711      * {@link WifiManager#WIFI_STATE_ENABLED},
712      * {@link WifiManager#WIFI_STATE_ENABLING},
713      * {@link WifiManager#WIFI_STATE_UNKNOWN}
714      */
715     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
716 
717     /**
718      * Work source to use to blame usage on the WiFi service
719      */
720     public static final WorkSource WIFI_WORK_SOURCE = new WorkSource(Process.WIFI_UID);
721 
722     private final BatteryStatsManager mBatteryStatsManager;
723 
724     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
725 
726 
727     // Used for debug and stats gathering
728     private static int sScanAlarmIntentCount = 0;
729 
730     private FrameworkFacade mFacade;
731     private WifiStateTracker mWifiStateTracker;
732     private final BackupManagerProxy mBackupManagerProxy;
733     private final WrongPasswordNotifier mWrongPasswordNotifier;
734     private final EapFailureNotifier mEapFailureNotifier;
735     private final SimRequiredNotifier mSimRequiredNotifier;
736     private final ConnectionFailureNotifier mConnectionFailureNotifier;
737     private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
738     // Maximum duration to continue to log Wifi usability stats after a data stall is triggered.
739     @VisibleForTesting
740     public static final long DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS = 30 * 1000;
741     private long mDataStallTriggerTimeMs = -1;
742     private int mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
743 
ClientModeImpl(Context context, FrameworkFacade facade, Looper looper, UserManager userManager, WifiInjector wifiInjector, BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode, WifiNative wifiNative, WrongPasswordNotifier wrongPasswordNotifier, SarManager sarManager, WifiTrafficPoller wifiTrafficPoller, LinkProbeManager linkProbeManager, BatteryStatsManager batteryStatsManager, SupplicantStateTracker supplicantStateTracker, MboOceController mboOceController, WifiCarrierInfoManager wifiCarrierInfoManager, EapFailureNotifier eapFailureNotifier, SimRequiredNotifier simRequiredNotifier)744     public ClientModeImpl(Context context, FrameworkFacade facade, Looper looper,
745                             UserManager userManager, WifiInjector wifiInjector,
746                             BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode,
747                             WifiNative wifiNative, WrongPasswordNotifier wrongPasswordNotifier,
748                             SarManager sarManager, WifiTrafficPoller wifiTrafficPoller,
749                             LinkProbeManager linkProbeManager,
750                             BatteryStatsManager batteryStatsManager,
751                             SupplicantStateTracker supplicantStateTracker,
752                             MboOceController mboOceController,
753                             WifiCarrierInfoManager wifiCarrierInfoManager,
754                             EapFailureNotifier eapFailureNotifier,
755                             SimRequiredNotifier simRequiredNotifier) {
756         super(TAG, looper);
757         mWifiInjector = wifiInjector;
758         mWifiMetrics = mWifiInjector.getWifiMetrics();
759         mClock = wifiInjector.getClock();
760         mPropertyService = wifiInjector.getPropertyService();
761         mBuildProperties = wifiInjector.getBuildProperties();
762         mWifiScoreCard = wifiInjector.getWifiScoreCard();
763         mContext = context;
764         mFacade = facade;
765         mWifiNative = wifiNative;
766         mBackupManagerProxy = backupManagerProxy;
767         mWrongPasswordNotifier = wrongPasswordNotifier;
768         mEapFailureNotifier = eapFailureNotifier;
769         mSimRequiredNotifier = simRequiredNotifier;
770         mSarManager = sarManager;
771         mWifiTrafficPoller = wifiTrafficPoller;
772         mLinkProbeManager = linkProbeManager;
773         mMboOceController = mboOceController;
774         mWifiCarrierInfoManager = wifiCarrierInfoManager;
775         mNetworkAgentState = DetailedState.DISCONNECTED;
776 
777         mBatteryStatsManager = batteryStatsManager;
778         mWifiStateTracker = wifiInjector.getWifiStateTracker();
779 
780         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
781                 PackageManager.FEATURE_WIFI_DIRECT);
782 
783         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
784         mWifiConfigManager = mWifiInjector.getWifiConfigManager();
785 
786         mPasspointManager = mWifiInjector.getPasspointManager();
787 
788         mWifiMonitor = mWifiInjector.getWifiMonitor();
789         mWifiDiagnostics = mWifiInjector.getWifiDiagnostics();
790         mWifiPermissionsWrapper = mWifiInjector.getWifiPermissionsWrapper();
791         mWifiDataStall = mWifiInjector.getWifiDataStall();
792 
793         mWifiInfo = new ExtendedWifiInfo(context);
794         mSupplicantStateTracker = supplicantStateTracker;
795         mWifiConnectivityManager = mWifiInjector.makeWifiConnectivityManager(this);
796         mBssidBlocklistMonitor = mWifiInjector.getBssidBlocklistMonitor();
797         mConnectionFailureNotifier = mWifiInjector.makeConnectionFailureNotifier(
798                 mWifiConnectivityManager);
799 
800         mLinkProperties = new LinkProperties();
801         mMcastLockManagerFilterController = new McastLockManagerFilterController();
802         mActivityManager = context.getSystemService(ActivityManager.class);
803 
804         mLastBssid = null;
805         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
806         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
807         mLastSimBasedConnectionCarrierName = null;
808         mLastSignalLevel = -1;
809 
810         mCountryCode = countryCode;
811 
812         mWifiScoreReport = new WifiScoreReport(mWifiInjector.getScoringParams(), mClock,
813                 mWifiMetrics, mWifiInfo, mWifiNative, mBssidBlocklistMonitor,
814                 mWifiInjector.getWifiThreadRunner());
815 
816         mNetworkCapabilitiesFilter = new NetworkCapabilities.Builder()
817                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
818                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
819                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
820                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
821                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
822                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
823                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
824                 // TODO - needs to be a bit more dynamic
825                 .setLinkUpstreamBandwidthKbps(1024 * 1024)
826                 .setLinkDownstreamBandwidthKbps(1024 * 1024)
827                 .setNetworkSpecifier(new MatchAllNetworkSpecifier())
828                 .build();
829         // Make the network factories.
830         mNetworkFactory = mWifiInjector.makeWifiNetworkFactory(
831                 mNetworkCapabilitiesFilter, mWifiConnectivityManager);
832         // We can't filter untrusted network in the capabilities filter because a trusted
833         // network would still satisfy a request that accepts untrusted ones.
834         // We need a second network factory for untrusted network requests because we need a
835         // different score filter for these requests.
836         mUntrustedNetworkFactory = mWifiInjector.makeUntrustedWifiNetworkFactory(
837                 mNetworkCapabilitiesFilter, mWifiConnectivityManager);
838 
839         mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager();
840         mProcessingActionListeners = new ExternalCallbackTracker<>(getHandler());
841         mWifiHealthMonitor = mWifiInjector.getWifiHealthMonitor();
842 
843         IntentFilter filter = new IntentFilter();
844         filter.addAction(Intent.ACTION_SCREEN_ON);
845         filter.addAction(Intent.ACTION_SCREEN_OFF);
846         mContext.registerReceiver(
847                 new BroadcastReceiver() {
848                     @Override
849                     public void onReceive(Context context, Intent intent) {
850                         String action = intent.getAction();
851 
852                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
853                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
854                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
855                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
856                         }
857                     }
858                 }, filter);
859 
860         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
861 
862         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
863         mSuspendWakeLock.setReferenceCounted(false);
864 
865         mWifiConfigManager.addOnNetworkUpdateListener(new OnNetworkUpdateListener());
866 
867         // CHECKSTYLE:OFF IndentationCheck
868         addState(mDefaultState);
869             addState(mConnectModeState, mDefaultState);
870                 addState(mL2ConnectedState, mConnectModeState);
871                     addState(mObtainingIpState, mL2ConnectedState);
872                     addState(mConnectedState, mL2ConnectedState);
873                     addState(mRoamingState, mL2ConnectedState);
874                 addState(mDisconnectingState, mConnectModeState);
875                 addState(mDisconnectedState, mConnectModeState);
876         // CHECKSTYLE:ON IndentationCheck
877 
878         setInitialState(mDefaultState);
879 
880         setLogRecSize(NUM_LOG_RECS_NORMAL);
881         setLogOnlyTransitions(false);
882     }
883 
884     @Override
start()885     public void start() {
886         super.start();
887 
888         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
889 
890         // Learn the initial state of whether the screen is on.
891         // We update this field when we receive broadcasts from the system.
892         handleScreenStateChanged(powerManager.isInteractive());
893     }
894 
registerForWifiMonitorEvents()895     private void registerForWifiMonitorEvents()  {
896         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.TARGET_BSSID_EVENT, getHandler());
897         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATED_BSSID_EVENT,
898                 getHandler());
899         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ANQP_DONE_EVENT, getHandler());
900         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
901                 getHandler());
902         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
903                 getHandler());
904         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_DONE_EVENT,
905                 getHandler());
906         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_START_EVENT,
907                 getHandler());
908         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.HS20_REMEDIATION_EVENT,
909                 getHandler());
910         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
911                 getHandler());
912         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.FILS_NETWORK_CONNECTION_EVENT,
913                 getHandler());
914         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
915                 getHandler());
916         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
917                 getHandler());
918         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
919                 getHandler());
920         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_IDENTITY,
921                 getHandler());
922         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_SIM_AUTH,
923                 getHandler());
924         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
925                 mWifiMetrics.getHandler());
926         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
927                 mWifiMetrics.getHandler());
928         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
929                 mWifiMetrics.getHandler());
930         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
931                 mWifiMetrics.getHandler());
932         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
933                 mWifiMetrics.getHandler());
934         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATED_BSSID_EVENT,
935                 mWifiMetrics.getHandler());
936         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.TARGET_BSSID_EVENT,
937                 mWifiMetrics.getHandler());
938         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
939                 mWifiInjector.getWifiLastResortWatchdog().getHandler());
940         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
941                 mSupplicantStateTracker.getHandler());
942         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
943                 mSupplicantStateTracker.getHandler());
944         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
945                 mSupplicantStateTracker.getHandler());
946         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE,
947                 getHandler());
948     }
949 
setMulticastFilter(boolean enabled)950     private void setMulticastFilter(boolean enabled) {
951         if (mIpClient != null) {
952             mIpClient.setMulticastFilter(enabled);
953         }
954     }
955 
956     /**
957      * Class to implement the MulticastLockManager.FilterController callback.
958      */
959     class McastLockManagerFilterController implements WifiMulticastLockManager.FilterController {
960         /**
961          * Start filtering Multicast v4 packets
962          */
startFilteringMulticastPackets()963         public void startFilteringMulticastPackets() {
964             setMulticastFilter(true);
965         }
966 
967         /**
968          * Stop filtering Multicast v4 packets
969          */
stopFilteringMulticastPackets()970         public void stopFilteringMulticastPackets() {
971             setMulticastFilter(false);
972         }
973     }
974 
975     class IpClientCallbacksImpl extends IpClientCallbacks {
976         private final ConditionVariable mWaitForCreationCv = new ConditionVariable(false);
977         private final ConditionVariable mWaitForStopCv = new ConditionVariable(false);
978 
979         @Override
onIpClientCreated(IIpClient ipClient)980         public void onIpClientCreated(IIpClient ipClient) {
981             mIpClient = new IpClientManager(ipClient, getName());
982             mWaitForCreationCv.open();
983         }
984 
985         @Override
onPreDhcpAction()986         public void onPreDhcpAction() {
987             sendMessage(CMD_PRE_DHCP_ACTION);
988         }
989 
990         @Override
onPostDhcpAction()991         public void onPostDhcpAction() {
992             sendMessage(CMD_POST_DHCP_ACTION);
993         }
994 
995         @Override
onNewDhcpResults(DhcpResultsParcelable dhcpResults)996         public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
997             if (dhcpResults != null) {
998                 sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, dhcpResults);
999             } else {
1000                 sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
1001             }
1002         }
1003 
1004         @Override
onProvisioningSuccess(LinkProperties newLp)1005         public void onProvisioningSuccess(LinkProperties newLp) {
1006             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL);
1007             sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1008             sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
1009         }
1010 
1011         @Override
onProvisioningFailure(LinkProperties newLp)1012         public void onProvisioningFailure(LinkProperties newLp) {
1013             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST);
1014             sendMessage(CMD_IP_CONFIGURATION_LOST);
1015         }
1016 
1017         @Override
onLinkPropertiesChange(LinkProperties newLp)1018         public void onLinkPropertiesChange(LinkProperties newLp) {
1019             sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1020         }
1021 
1022         @Override
onReachabilityLost(String logMsg)1023         public void onReachabilityLost(String logMsg) {
1024             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_REACHABILITY_LOST);
1025             sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
1026         }
1027 
1028         @Override
installPacketFilter(byte[] filter)1029         public void installPacketFilter(byte[] filter) {
1030             sendMessage(CMD_INSTALL_PACKET_FILTER, filter);
1031         }
1032 
1033         @Override
startReadPacketFilter()1034         public void startReadPacketFilter() {
1035             sendMessage(CMD_READ_PACKET_FILTER);
1036         }
1037 
1038         @Override
setFallbackMulticastFilter(boolean enabled)1039         public void setFallbackMulticastFilter(boolean enabled) {
1040             sendMessage(CMD_SET_FALLBACK_PACKET_FILTERING, enabled);
1041         }
1042 
1043         @Override
setNeighborDiscoveryOffload(boolean enabled)1044         public void setNeighborDiscoveryOffload(boolean enabled) {
1045             sendMessage(CMD_CONFIG_ND_OFFLOAD, (enabled ? 1 : 0));
1046         }
1047 
1048         @Override
onPreconnectionStart(List<Layer2PacketParcelable> packets)1049         public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {
1050             sendMessage(CMD_START_FILS_CONNECTION, 0, 0, packets);
1051         }
1052 
1053         @Override
onQuit()1054         public void onQuit() {
1055             mWaitForStopCv.open();
1056         }
1057 
awaitCreation()1058         boolean awaitCreation() {
1059             return mWaitForCreationCv.block(IPCLIENT_STARTUP_TIMEOUT_MS);
1060         }
1061 
awaitShutdown()1062         boolean awaitShutdown() {
1063             return mWaitForStopCv.block(IPCLIENT_SHUTDOWN_TIMEOUT_MS);
1064         }
1065     }
1066 
stopIpClient()1067     private void stopIpClient() {
1068         // TODO(b/157943924): Adding more log to debug the issue.
1069         Log.v(TAG, "stopIpClient IpClientWithPreConnection: " + mIpClientWithPreConnection,
1070                 new Throwable());
1071         if (mIpClient != null) {
1072             if (mIpClientWithPreConnection) {
1073                 mIpClient.notifyPreconnectionComplete(false);
1074             }
1075             mIpClient.stop();
1076         }
1077         mIpClientWithPreConnection = false;
1078         mSentHLPs = false;
1079     }
1080 
stopDhcpSetup()1081     private void stopDhcpSetup() {
1082         /* Restore power save and suspend optimizations */
1083         handlePostDhcpSetup();
1084         stopIpClient();
1085     }
1086 
1087     /**
1088      * Listener for config manager network config related events.
1089      * TODO (b/117601161) : Move some of the existing handling in WifiConnectivityManager's listener
1090      * for the same events.
1091      */
1092     private class OnNetworkUpdateListener implements
1093             WifiConfigManager.OnNetworkUpdateListener {
1094         @Override
onNetworkAdded(WifiConfiguration config)1095         public void onNetworkAdded(WifiConfiguration config) { }
1096 
1097         @Override
onNetworkEnabled(WifiConfiguration config)1098         public void onNetworkEnabled(WifiConfiguration config) { }
1099 
1100         @Override
onNetworkRemoved(WifiConfiguration config)1101         public void onNetworkRemoved(WifiConfiguration config) {
1102             // The current connected or connecting network has been removed, trigger a disconnect.
1103             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1104                 // Disconnect and let autojoin reselect a new network
1105                 sendMessage(CMD_DISCONNECT);
1106             }
1107             mWifiNative.removeNetworkCachedData(config.networkId);
1108         }
1109 
1110         @Override
onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig)1111         public void onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig) {
1112             // Clear invalid cached data.
1113             mWifiNative.removeNetworkCachedData(oldConfig.networkId);
1114 
1115             // Check if user/app change meteredOverride for connected network.
1116             if (newConfig.networkId != mLastNetworkId
1117                     || newConfig.meteredOverride == oldConfig.meteredOverride) {
1118                 // nothing to do.
1119                 return;
1120             }
1121             boolean isMetered = WifiConfiguration.isMetered(newConfig, mWifiInfo);
1122             boolean wasMetered = WifiConfiguration.isMetered(oldConfig, mWifiInfo);
1123             if (isMetered == wasMetered) {
1124                 // no meteredness change, nothing to do.
1125                 if (mVerboseLoggingEnabled) {
1126                     Log.v(TAG, "User/app changed meteredOverride, but no change in meteredness");
1127                 }
1128                 return;
1129             }
1130             // If unmetered->metered trigger a disconnect.
1131             // If metered->unmetered update capabilities.
1132             if (isMetered) {
1133                 Log.w(TAG, "Network marked metered, triggering disconnect");
1134                 sendMessage(CMD_DISCONNECT);
1135             } else {
1136                 Log.i(TAG, "Network marked unmetered, triggering capabilities update");
1137                 updateCapabilities(newConfig);
1138             }
1139         }
1140 
1141         @Override
onNetworkTemporarilyDisabled(WifiConfiguration config, int disableReason)1142         public void onNetworkTemporarilyDisabled(WifiConfiguration config, int disableReason) {
1143             if (disableReason == DISABLED_NO_INTERNET_TEMPORARY) return;
1144             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1145                 // Disconnect and let autojoin reselect a new network
1146                 sendMessage(CMD_DISCONNECT);
1147             }
1148 
1149         }
1150 
1151         @Override
onNetworkPermanentlyDisabled(WifiConfiguration config, int disableReason)1152         public void onNetworkPermanentlyDisabled(WifiConfiguration config, int disableReason) {
1153             // For DISABLED_NO_INTERNET_PERMANENT we do not need to remove the network
1154             // because supplicant won't be trying to reconnect. If this is due to a
1155             // preventAutomaticReconnect request from ConnectivityService, that service
1156             // will disconnect as appropriate.
1157             if (disableReason == DISABLED_NO_INTERNET_PERMANENT) return;
1158             if (config.networkId == mTargetNetworkId || config.networkId == mLastNetworkId) {
1159                 // Disconnect and let autojoin reselect a new network
1160                 sendMessage(CMD_DISCONNECT);
1161             }
1162         }
1163     }
1164 
1165     /**
1166      * Set wpa_supplicant log level using |mVerboseLoggingLevel| flag.
1167      */
setSupplicantLogLevel()1168     void setSupplicantLogLevel() {
1169         mWifiNative.setSupplicantLogLevel(mVerboseLoggingEnabled);
1170     }
1171 
1172     /**
1173      * Method to update logging level in wifi service related classes.
1174      *
1175      * @param verbose int logging level to use
1176      */
enableVerboseLogging(int verbose)1177     public void enableVerboseLogging(int verbose) {
1178         if (verbose > 0) {
1179             mVerboseLoggingEnabled = true;
1180             setLogRecSize(mActivityManager.isLowRamDevice()
1181                     ? NUM_LOG_RECS_VERBOSE_LOW_MEMORY : NUM_LOG_RECS_VERBOSE);
1182         } else {
1183             mVerboseLoggingEnabled = false;
1184             setLogRecSize(NUM_LOG_RECS_NORMAL);
1185         }
1186         setSupplicantLogLevel();
1187         mCountryCode.enableVerboseLogging(verbose);
1188         mWifiScoreReport.enableVerboseLogging(mVerboseLoggingEnabled);
1189         mWifiDiagnostics.enableVerboseLogging(mVerboseLoggingEnabled);
1190         mWifiMonitor.enableVerboseLogging(verbose);
1191         mWifiNative.enableVerboseLogging(verbose);
1192         mWifiConfigManager.enableVerboseLogging(verbose);
1193         mSupplicantStateTracker.enableVerboseLogging(verbose);
1194         mPasspointManager.enableVerboseLogging(verbose);
1195         mNetworkFactory.enableVerboseLogging(verbose);
1196         mLinkProbeManager.enableVerboseLogging(mVerboseLoggingEnabled);
1197         mMboOceController.enableVerboseLogging(mVerboseLoggingEnabled);
1198         mWifiScoreCard.enableVerboseLogging(mVerboseLoggingEnabled);
1199         mWifiHealthMonitor.enableVerboseLogging(mVerboseLoggingEnabled);
1200         mWifiInjector.getThroughputPredictor().enableVerboseLogging(mVerboseLoggingEnabled);
1201         mWifiDataStall.enableVerboseLogging(mVerboseLoggingEnabled);
1202         mWifiConnectivityManager.enableVerboseLogging(mVerboseLoggingEnabled);
1203     }
1204 
1205     /**
1206      * Initiates connection to a network specified by the user/app. This method checks if the
1207      * requesting app holds the NETWORK_SETTINGS permission.
1208      *
1209      * @param netId Id network to initiate connection.
1210      * @param uid UID of the app requesting the connection.
1211      * @param forceReconnect Whether to force a connection even if we're connected to the same
1212      *                       network currently.
1213      */
connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect)1214     private void connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) {
1215         logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid
1216                 + ", forceReconnect = " + forceReconnect);
1217         if (!forceReconnect && (mLastNetworkId == netId || mTargetNetworkId == netId)) {
1218             // We're already connecting/connected to the user specified network, don't trigger a
1219             // reconnection unless it was forced.
1220             logi("connectToUserSelectNetwork already connecting/connected=" + netId);
1221         } else {
1222             mWifiConnectivityManager.prepareForForcedConnection(netId);
1223             if (uid == Process.SYSTEM_UID) {
1224                 mWifiMetrics.setNominatorForNetwork(netId,
1225                         WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL);
1226             }
1227             startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
1228         }
1229     }
1230 
1231     /**
1232      * ******************************************************
1233      * Methods exposed for public use
1234      * ******************************************************
1235      */
1236 
1237     /**
1238      * Retrieve a Messenger for the ClientModeImpl Handler
1239      *
1240      * @return Messenger
1241      */
getMessenger()1242     public Messenger getMessenger() {
1243         return new Messenger(getHandler());
1244     }
1245 
1246     // Last connect attempt is used to prevent scan requests:
1247     //  - for a period of 10 seconds after attempting to connect
1248     private long mLastConnectAttemptTimestamp = 0;
1249 
1250     // For debugging, keep track of last message status handling
1251     // TODO, find an equivalent mechanism as part of parent class
1252     private static final int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
1253     private static final int MESSAGE_HANDLING_STATUS_OK = 1;
1254     private static final int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
1255     private static final int MESSAGE_HANDLING_STATUS_REFUSED = -1;
1256     private static final int MESSAGE_HANDLING_STATUS_FAIL = -2;
1257     private static final int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
1258     private static final int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
1259     private static final int MESSAGE_HANDLING_STATUS_DISCARD = -5;
1260     private static final int MESSAGE_HANDLING_STATUS_LOOPED = -6;
1261     private static final int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
1262 
1263     private int mMessageHandlingStatus = 0;
1264 
1265     private int mOnTime = 0;
1266     private int mTxTime = 0;
1267     private int mRxTime = 0;
1268 
1269     private int mOnTimeScreenStateChange = 0;
1270     private long mLastOntimeReportTimeStamp = 0;
1271     private long mLastScreenStateChangeTimeStamp = 0;
1272     private int mOnTimeLastReport = 0;
1273     private int mTxTimeLastReport = 0;
1274     private int mRxTimeLastReport = 0;
1275 
1276     private WifiLinkLayerStats mLastLinkLayerStats;
1277     private long mLastLinkLayerStatsUpdate = 0;
1278 
reportOnTime()1279     String reportOnTime() {
1280         long now = mClock.getWallClockMillis();
1281         StringBuilder sb = new StringBuilder();
1282         // Report stats since last report
1283         int on = mOnTime - mOnTimeLastReport;
1284         mOnTimeLastReport = mOnTime;
1285         int tx = mTxTime - mTxTimeLastReport;
1286         mTxTimeLastReport = mTxTime;
1287         int rx = mRxTime - mRxTimeLastReport;
1288         mRxTimeLastReport = mRxTime;
1289         int period = (int) (now - mLastOntimeReportTimeStamp);
1290         mLastOntimeReportTimeStamp = now;
1291         sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
1292         // Report stats since Screen State Changed
1293         on = mOnTime - mOnTimeScreenStateChange;
1294         period = (int) (now - mLastScreenStateChangeTimeStamp);
1295         sb.append(String.format(" from screen [on:%d period:%d]", on, period));
1296         return sb.toString();
1297     }
1298 
getWifiLinkLayerStats()1299     WifiLinkLayerStats getWifiLinkLayerStats() {
1300         if (mInterfaceName == null) {
1301             loge("getWifiLinkLayerStats called without an interface");
1302             return null;
1303         }
1304         mLastLinkLayerStatsUpdate = mClock.getWallClockMillis();
1305         WifiLinkLayerStats stats = mWifiNative.getWifiLinkLayerStats(mInterfaceName);
1306         if (stats != null) {
1307             mOnTime = stats.on_time;
1308             mTxTime = stats.tx_time;
1309             mRxTime = stats.rx_time;
1310             mRunningBeaconCount = stats.beacon_rx;
1311             mWifiInfo.updatePacketRates(stats, mLastLinkLayerStatsUpdate);
1312         } else {
1313             long mTxPkts = mFacade.getTxPackets(mInterfaceName);
1314             long mRxPkts = mFacade.getRxPackets(mInterfaceName);
1315             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts, mLastLinkLayerStatsUpdate);
1316         }
1317         return stats;
1318     }
1319 
1320     /**
1321      * Check if a Wi-Fi band is supported
1322      *
1323      * @param band A value from {@link WifiScanner.WIFI_BAND_5_GHZ} or
1324      *        {@link WifiScanner.WIFI_BAND_6_GHZ}
1325      * @return {@code true} if band is supported, {@code false} otherwise.
1326      */
isWifiBandSupported(int band)1327     public boolean isWifiBandSupported(int band) {
1328         if (band == WifiScanner.WIFI_BAND_5_GHZ) {
1329             // In some cases, devices override the value by the overlay configs
1330             if (mContext.getResources().getBoolean(R.bool.config_wifi5ghzSupport)) {
1331                 return true;
1332             }
1333             return (mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ).length > 0);
1334         }
1335 
1336         if (band == WifiScanner.WIFI_BAND_6_GHZ) {
1337             if (mContext.getResources().getBoolean(R.bool.config_wifi6ghzSupport)) {
1338                 return true;
1339             }
1340             return (mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ).length > 0);
1341         }
1342 
1343         return false;
1344     }
1345 
1346     /**
1347      * Update interface capabilities
1348      * This method is used to update some of interface capabilities defined in overlay
1349      *
1350      * @param ifaceName name of interface to update
1351      */
updateInterfaceCapabilities(@onNull String ifaceName)1352     private void updateInterfaceCapabilities(@NonNull String ifaceName) {
1353         DeviceWiphyCapabilities cap = mWifiNative.getDeviceWiphyCapabilities(ifaceName);
1354         if (cap != null) {
1355             // Some devices don't have support of 11ax indicated by the chip,
1356             // so an override config value is used
1357             if (mContext.getResources().getBoolean(R.bool.config_wifi11axSupportOverride)) {
1358                 cap.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, true);
1359             }
1360 
1361             mWifiNative.setDeviceWiphyCapabilities(ifaceName, cap);
1362         }
1363     }
1364 
1365     /**
1366      * Check if a Wi-Fi standard is supported
1367      *
1368      * @param standard A value from {@link ScanResult}'s {@code WIFI_STANDARD_}
1369      * @return {@code true} if standard is supported, {@code false} otherwise.
1370      */
isWifiStandardSupported(@ifiStandard int standard)1371     public boolean isWifiStandardSupported(@WifiStandard int standard) {
1372         return mWifiNative.isWifiStandardSupported(mInterfaceName, standard);
1373     }
1374 
getDstMacForKeepalive(KeepalivePacketData packetData)1375     private byte[] getDstMacForKeepalive(KeepalivePacketData packetData)
1376             throws InvalidPacketException {
1377         try {
1378             InetAddress gateway = NetUtils.selectBestRoute(
1379                     mLinkProperties.getRoutes(), packetData.getDstAddress()).getGateway();
1380             String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
1381             return NativeUtil.macAddressToByteArray(dstMacStr);
1382         } catch (NullPointerException | IllegalArgumentException e) {
1383             throw new InvalidPacketException(InvalidPacketException.ERROR_INVALID_IP_ADDRESS);
1384         }
1385     }
1386 
getEtherProtoForKeepalive(KeepalivePacketData packetData)1387     private static int getEtherProtoForKeepalive(KeepalivePacketData packetData)
1388             throws InvalidPacketException {
1389         if (packetData.getDstAddress() instanceof Inet4Address) {
1390             return OsConstants.ETH_P_IP;
1391         } else if (packetData.getDstAddress() instanceof Inet6Address) {
1392             return OsConstants.ETH_P_IPV6;
1393         } else {
1394             throw new InvalidPacketException(InvalidPacketException.ERROR_INVALID_IP_ADDRESS);
1395         }
1396     }
1397 
startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds)1398     private int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData,
1399             int intervalSeconds) {
1400         byte[] packet = null;
1401         byte[] dstMac = null;
1402         int proto = 0;
1403 
1404         try {
1405             packet = packetData.getPacket();
1406             dstMac = getDstMacForKeepalive(packetData);
1407             proto = getEtherProtoForKeepalive(packetData);
1408         } catch (InvalidPacketException e) {
1409             return e.getError();
1410         }
1411 
1412         int ret = mWifiNative.startSendingOffloadedPacket(
1413                 mInterfaceName, slot, dstMac, packet, proto, intervalSeconds * 1000);
1414         if (ret != 0) {
1415             loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds
1416                     + "): hardware error " + ret);
1417             return SocketKeepalive.ERROR_HARDWARE_ERROR;
1418         } else {
1419             return SocketKeepalive.SUCCESS;
1420         }
1421     }
1422 
stopWifiIPPacketOffload(int slot)1423     private int stopWifiIPPacketOffload(int slot) {
1424         int ret = mWifiNative.stopSendingOffloadedPacket(mInterfaceName, slot);
1425         if (ret != 0) {
1426             loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret);
1427             return SocketKeepalive.ERROR_HARDWARE_ERROR;
1428         } else {
1429             return SocketKeepalive.SUCCESS;
1430         }
1431     }
1432 
startRssiMonitoringOffload(byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiHandler)1433     private int startRssiMonitoringOffload(byte maxRssi, byte minRssi,
1434             WifiNative.WifiRssiEventHandler rssiHandler) {
1435         return mWifiNative.startRssiMonitoring(mInterfaceName, maxRssi, minRssi, rssiHandler);
1436     }
1437 
stopRssiMonitoringOffload()1438     private int stopRssiMonitoringOffload() {
1439         return mWifiNative.stopRssiMonitoring(mInterfaceName);
1440     }
1441 
1442     /**
1443      * Temporary method that allows the active ClientModeManager to set the wifi state that is
1444      * retrieved by API calls. This will be removed when WifiServiceImpl no longer directly calls
1445      * this class (b/31479117).
1446      *
1447      * @param newState new state to set, invalid states are ignored.
1448      */
setWifiStateForApiCalls(int newState)1449     public void setWifiStateForApiCalls(int newState) {
1450         switch (newState) {
1451             case WIFI_STATE_DISABLING:
1452             case WIFI_STATE_DISABLED:
1453             case WIFI_STATE_ENABLING:
1454             case WIFI_STATE_ENABLED:
1455             case WIFI_STATE_UNKNOWN:
1456                 if (mVerboseLoggingEnabled) {
1457                     Log.d(TAG, "setting wifi state to: " + newState);
1458                 }
1459                 mWifiState.set(newState);
1460                 return;
1461             default:
1462                 Log.d(TAG, "attempted to set an invalid state: " + newState);
1463                 return;
1464         }
1465     }
1466 
1467     /**
1468      * Method used by WifiServiceImpl to get the current state of Wifi (in client mode) for API
1469      * calls.  This will be removed when WifiService no longer directly calls this class
1470      * (b/31479117).
1471      */
syncGetWifiState()1472     public int syncGetWifiState() {
1473         return mWifiState.get();
1474     }
1475 
1476     /**
1477      * Converts the current wifi state to a printable form.
1478      */
syncGetWifiStateByName()1479     public String syncGetWifiStateByName() {
1480         switch (mWifiState.get()) {
1481             case WIFI_STATE_DISABLING:
1482                 return "disabling";
1483             case WIFI_STATE_DISABLED:
1484                 return "disabled";
1485             case WIFI_STATE_ENABLING:
1486                 return "enabling";
1487             case WIFI_STATE_ENABLED:
1488                 return "enabled";
1489             case WIFI_STATE_UNKNOWN:
1490                 return "unknown state";
1491             default:
1492                 return "[invalid state]";
1493         }
1494     }
1495 
isConnected()1496     public boolean isConnected() {
1497         return getCurrentState() == mConnectedState;
1498     }
1499 
isDisconnected()1500     public boolean isDisconnected() {
1501         return getCurrentState() == mDisconnectedState;
1502     }
1503 
1504     /**
1505      * Method checking if supplicant is in a transient state
1506      *
1507      * @return boolean true if in transient state
1508      */
isSupplicantTransientState()1509     public boolean isSupplicantTransientState() {
1510         SupplicantState supplicantState = mWifiInfo.getSupplicantState();
1511         if (supplicantState == SupplicantState.ASSOCIATING
1512                 || supplicantState == SupplicantState.AUTHENTICATING
1513                 || supplicantState == SupplicantState.FOUR_WAY_HANDSHAKE
1514                 || supplicantState == SupplicantState.GROUP_HANDSHAKE) {
1515 
1516             if (mVerboseLoggingEnabled) {
1517                 Log.d(TAG, "Supplicant is under transient state: " + supplicantState);
1518             }
1519             return true;
1520         } else {
1521             if (mVerboseLoggingEnabled) {
1522                 Log.d(TAG, "Supplicant is under steady state: " + supplicantState);
1523             }
1524         }
1525 
1526         return false;
1527     }
1528 
1529     /**
1530      * Get status information for the current connection, if any.
1531      *
1532      * @return a {@link WifiInfo} object containing information about the current connection
1533      */
syncRequestConnectionInfo()1534     public WifiInfo syncRequestConnectionInfo() {
1535         WifiInfo result = new WifiInfo(mWifiInfo);
1536         return result;
1537     }
1538 
1539     /**
1540      * Method to retrieve the current WifiInfo
1541      *
1542      * @returns WifiInfo
1543      */
getWifiInfo()1544     public WifiInfo getWifiInfo() {
1545         return mWifiInfo;
1546     }
1547 
1548     /**
1549      * Blocking call to get the current DHCP results
1550      *
1551      * @return DhcpResultsParcelable current results
1552      */
1553     @NonNull
syncGetDhcpResultsParcelable()1554     public DhcpResultsParcelable syncGetDhcpResultsParcelable() {
1555         synchronized (mDhcpResultsParcelableLock) {
1556             return mDhcpResultsParcelable;
1557         }
1558     }
1559 
1560     /**
1561      * When the underlying interface is destroyed, we must immediately tell connectivity service to
1562      * mark network agent as disconnected and stop the ip client.
1563      */
handleIfaceDestroyed()1564     public void handleIfaceDestroyed() {
1565         handleNetworkDisconnect();
1566     }
1567 
1568     /**
1569      * TODO: doc
1570      */
setOperationalMode(int mode, String ifaceName)1571     public void setOperationalMode(int mode, String ifaceName) {
1572         if (mVerboseLoggingEnabled) {
1573             log("setting operational mode to " + String.valueOf(mode) + " for iface: " + ifaceName);
1574         }
1575         mModeChange = true;
1576         if (mode != CONNECT_MODE) {
1577             // we are disabling client mode...   need to exit connect mode now
1578             transitionTo(mDefaultState);
1579         } else {
1580             // do a quick sanity check on the iface name, make sure it isn't null
1581             if (ifaceName != null) {
1582                 mInterfaceName = ifaceName;
1583                 updateInterfaceCapabilities(ifaceName);
1584                 transitionTo(mDisconnectedState);
1585                 mWifiScoreReport.setInterfaceName(ifaceName);
1586             } else {
1587                 Log.e(TAG, "supposed to enter connect mode, but iface is null -> DefaultState");
1588                 transitionTo(mDefaultState);
1589             }
1590         }
1591         // use the CMD_SET_OPERATIONAL_MODE to force the transitions before other messages are
1592         // handled.
1593         sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE);
1594     }
1595 
checkAbnormalConnectionFailureAndTakeBugReport(String ssid)1596     private void checkAbnormalConnectionFailureAndTakeBugReport(String ssid) {
1597         if (mWifiInjector.getDeviceConfigFacade()
1598                 .isAbnormalConnectionFailureBugreportEnabled()) {
1599             int reasonCode = mWifiScoreCard.detectAbnormalConnectionFailure(ssid);
1600             if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) {
1601                 String bugTitle = "Wi-Fi BugReport";
1602                 String bugDetail = "Detect abnormal "
1603                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1604                 takeBugReport(bugTitle, bugDetail);
1605             }
1606         }
1607     }
1608 
checkAbnormalDisconnectionAndTakeBugReport()1609     private void checkAbnormalDisconnectionAndTakeBugReport() {
1610         if (mWifiInjector.getDeviceConfigFacade()
1611                 .isAbnormalDisconnectionBugreportEnabled()) {
1612             int reasonCode = mWifiScoreCard.detectAbnormalDisconnection();
1613             if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) {
1614                 String bugTitle = "Wi-Fi BugReport";
1615                 String bugDetail = "Detect abnormal "
1616                         + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode];
1617                 takeBugReport(bugTitle, bugDetail);
1618             }
1619         }
1620     }
1621 
1622     /**
1623      * Initiates a system-level bugreport, in a non-blocking fashion.
1624      */
takeBugReport(String bugTitle, String bugDetail)1625     public void takeBugReport(String bugTitle, String bugDetail) {
1626         mWifiDiagnostics.takeBugReport(bugTitle, bugDetail);
1627     }
1628 
1629     /**
1630      * Allow tests to confirm the operational mode for ClientModeImpl for testing.
1631      */
1632     @VisibleForTesting
getOperationalModeForTest()1633     protected int getOperationalModeForTest() {
1634         return mOperationalMode;
1635     }
1636 
1637     /**
1638      * Retrieve the WifiMulticastLockManager.FilterController callback for registration.
1639      */
getMcastLockManagerFilterController()1640     protected WifiMulticastLockManager.FilterController getMcastLockManagerFilterController() {
1641         return mMcastLockManagerFilterController;
1642     }
1643 
1644     /**
1645      * Blocking method to retrieve the passpoint icon.
1646      *
1647      * @param channel AsyncChannel for the response
1648      * @param bssid representation of the bssid as a long
1649      * @param fileName name of the file
1650      *
1651      * @return boolean returning the result of the call
1652      */
syncQueryPasspointIcon(AsyncChannel channel, long bssid, String fileName)1653     public boolean syncQueryPasspointIcon(AsyncChannel channel, long bssid, String fileName) {
1654         Bundle bundle = new Bundle();
1655         bundle.putLong(EXTRA_OSU_ICON_QUERY_BSSID, bssid);
1656         bundle.putString(EXTRA_OSU_ICON_QUERY_FILENAME, fileName);
1657         Message resultMsg = channel.sendMessageSynchronously(CMD_QUERY_OSU_ICON, bundle);
1658         int result = resultMsg.arg1;
1659         resultMsg.recycle();
1660         return result == 1;
1661     }
1662 
1663     /**
1664      * Deauthenticate and set the re-authentication hold off time for the current network
1665      * @param holdoff hold off time in milliseconds
1666      * @param ess set if the hold off pertains to an ESS rather than a BSS
1667      */
deauthenticateNetwork(AsyncChannel channel, long holdoff, boolean ess)1668     public void deauthenticateNetwork(AsyncChannel channel, long holdoff, boolean ess) {
1669         // TODO: This needs an implementation
1670     }
1671 
1672     /**
1673      * Disconnect from Access Point
1674      */
disconnectCommand()1675     public void disconnectCommand() {
1676         sendMessage(CMD_DISCONNECT);
1677     }
1678 
1679     /**
1680      * Method to trigger a disconnect.
1681      *
1682      * @param uid UID of requesting caller
1683      * @param reason disconnect reason
1684      */
disconnectCommand(int uid, int reason)1685     public void disconnectCommand(int uid, int reason) {
1686         sendMessage(CMD_DISCONNECT, uid, reason);
1687     }
1688 
1689     /**
1690      * Initiate a reconnection to AP
1691      */
reconnectCommand(WorkSource workSource)1692     public void reconnectCommand(WorkSource workSource) {
1693         sendMessage(CMD_RECONNECT, workSource);
1694     }
1695 
1696     /**
1697      * Initiate a re-association to AP
1698      */
reassociateCommand()1699     public void reassociateCommand() {
1700         sendMessage(CMD_REASSOCIATE);
1701     }
1702 
1703     /**
1704      * Checks for a null Message.
1705      *
1706      * This can happen with sendMessageSynchronously, for example if an
1707      * InterruptedException occurs. If this just happens once, silently
1708      * ignore it, because it is probably a side effect of shutting down.
1709      * If it happens a second time, generate a WTF.
1710      */
messageIsNull(Message resultMsg)1711     private boolean messageIsNull(Message resultMsg) {
1712         if (resultMsg != null) return false;
1713         if (mNullMessageCounter.getAndIncrement() > 0) {
1714             Log.wtf(TAG, "Persistent null Message", new RuntimeException());
1715         }
1716         return true;
1717     }
1718     private AtomicInteger mNullMessageCounter = new AtomicInteger(0);
1719 
1720     /**
1721      * Start subscription provisioning synchronously
1722      *
1723      * @param provider {@link OsuProvider} the provider to provision with
1724      * @param callback {@link IProvisioningCallback} callback for provisioning status
1725      * @return boolean true indicates provisioning was started, false otherwise
1726      */
syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, IProvisioningCallback callback, AsyncChannel channel)1727     public boolean syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider,
1728             IProvisioningCallback callback, AsyncChannel channel) {
1729         Message msg = Message.obtain();
1730         msg.what = CMD_START_SUBSCRIPTION_PROVISIONING;
1731         msg.arg1 = callingUid;
1732         msg.obj = callback;
1733         msg.getData().putParcelable(EXTRA_OSU_PROVIDER, provider);
1734         Message resultMsg = channel.sendMessageSynchronously(msg);
1735         if (messageIsNull(resultMsg)) return false;
1736         boolean result = resultMsg.arg1 != 0;
1737         resultMsg.recycle();
1738         return result;
1739     }
1740 
1741     /**
1742      * Get the supported feature set synchronously
1743      */
syncGetSupportedFeatures(AsyncChannel channel)1744     public long syncGetSupportedFeatures(AsyncChannel channel) {
1745         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
1746         if (messageIsNull(resultMsg)) return 0;
1747         long supportedFeatureSet = ((Long) resultMsg.obj).longValue();
1748         resultMsg.recycle();
1749         return supportedFeatureSet;
1750     }
1751 
1752     /**
1753      * Get link layers stats for adapter synchronously
1754      */
syncGetLinkLayerStats(AsyncChannel channel)1755     public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
1756         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
1757         if (messageIsNull(resultMsg)) return null;
1758         WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
1759         resultMsg.recycle();
1760         return result;
1761     }
1762 
1763     /**
1764      * Method to enable/disable RSSI polling
1765      * @param enabled boolean idicating if polling should start
1766      */
enableRssiPolling(boolean enabled)1767     public void enableRssiPolling(boolean enabled) {
1768         sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
1769     }
1770 
1771     /**
1772      * Set high performance mode of operation.
1773      * Enabling would set active power mode and disable suspend optimizations;
1774      * disabling would set auto power mode and enable suspend optimizations
1775      *
1776      * @param enable true if enable, false otherwise
1777      */
setHighPerfModeEnabled(boolean enable)1778     public void setHighPerfModeEnabled(boolean enable) {
1779         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
1780     }
1781 
1782 
1783     /**
1784      * reset cached SIM credential data
1785      */
resetSimAuthNetworks(@esetSimReason int resetReason)1786     public synchronized void resetSimAuthNetworks(@ResetSimReason int resetReason) {
1787         sendMessage(CMD_RESET_SIM_NETWORKS, resetReason);
1788     }
1789 
1790     /**
1791      * Should only be used internally.
1792      * External callers should use {@link #syncGetCurrentNetwork(AsyncChannel)}.
1793      */
getCurrentNetwork()1794     private Network getCurrentNetwork() {
1795         if (mNetworkAgent != null) {
1796             return mNetworkAgent.getNetwork();
1797         } else {
1798             return null;
1799         }
1800     }
1801 
1802     /**
1803      * Get Network object of currently connected wifi network, or null if not connected.
1804      * @return Network object of current wifi network
1805      */
syncGetCurrentNetwork(AsyncChannel channel)1806     public Network syncGetCurrentNetwork(AsyncChannel channel) {
1807         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CURRENT_NETWORK);
1808         if (messageIsNull(resultMsg)) return null;
1809         Network network = (Network) resultMsg.obj;
1810         resultMsg.recycle();
1811         return network;
1812     }
1813 
1814     /**
1815      * Enable TDLS for a specific MAC address
1816      */
enableTdls(String remoteMacAddress, boolean enable)1817     public void enableTdls(String remoteMacAddress, boolean enable) {
1818         int enabler = enable ? 1 : 0;
1819         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
1820     }
1821 
1822     /**
1823      * Send a message indicating bluetooth adapter state changed, e.g., turn on or ff
1824      */
sendBluetoothAdapterStateChange(int state)1825     public void sendBluetoothAdapterStateChange(int state) {
1826         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
1827     }
1828 
1829     /**
1830      * Send a message indicating bluetooth adapter connection state changed, e.g., connected
1831      * or disconnected. Note that turning off BT after pairing success keeps connection state in
1832      * connected state.
1833      */
sendBluetoothAdapterConnectionStateChange(int state)1834     public void sendBluetoothAdapterConnectionStateChange(int state) {
1835         sendMessage(CMD_BLUETOOTH_ADAPTER_CONNECTION_STATE_CHANGE, state, 0);
1836     }
1837 
1838     /**
1839      * Trigger dump on the class IpClient object.
1840      */
dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args)1841     public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) {
1842         if (mIpClient != null) {
1843             // All dumpIpClient does is print this log message.
1844             // TODO: consider deleting this, since it's not useful.
1845             pw.println("IpClient logs have moved to dumpsys network_stack");
1846         }
1847     }
1848 
dhcpResultsParcelableToString(DhcpResultsParcelable dhcpResults)1849     private static String dhcpResultsParcelableToString(DhcpResultsParcelable dhcpResults) {
1850         return new StringBuilder()
1851                 .append("baseConfiguration ").append(dhcpResults.baseConfiguration)
1852                 .append("leaseDuration ").append(dhcpResults.leaseDuration)
1853                 .append("mtu ").append(dhcpResults.mtu)
1854                 .append("serverAddress ").append(dhcpResults.serverAddress)
1855                 .append("serverHostName ").append(dhcpResults.serverHostName)
1856                 .append("vendorInfo ").append(dhcpResults.vendorInfo)
1857                 .toString();
1858     }
1859 
1860     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1861     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1862         super.dump(fd, pw, args);
1863         mSupplicantStateTracker.dump(fd, pw, args);
1864         pw.println("mLinkProperties " + mLinkProperties);
1865         pw.println("mWifiInfo " + mWifiInfo);
1866         pw.println("mDhcpResultsParcelable "
1867                 + dhcpResultsParcelableToString(mDhcpResultsParcelable));
1868         pw.println("mLastSignalLevel " + mLastSignalLevel);
1869         pw.println("mLastBssid " + mLastBssid);
1870         pw.println("mLastNetworkId " + mLastNetworkId);
1871         pw.println("mLastSubId " + mLastSubId);
1872         pw.println("mLastSimBasedConnectionCarrierName " + mLastSimBasedConnectionCarrierName);
1873         pw.println("mOperationalMode " + mOperationalMode);
1874         pw.println("mSuspendOptimizationsEnabled " + mContext.getResources().getBoolean(
1875                 R.bool.config_wifiSuspendOptimizationsEnabled));
1876         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
1877         mCountryCode.dump(fd, pw, args);
1878         mNetworkFactory.dump(fd, pw, args);
1879         mUntrustedNetworkFactory.dump(fd, pw, args);
1880         pw.println("Wlan Wake Reasons:" + mWifiNative.getWlanWakeReasonCount());
1881         pw.println();
1882 
1883         mWifiConfigManager.dump(fd, pw, args);
1884         pw.println();
1885         mPasspointManager.dump(pw);
1886         pw.println();
1887         mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_USER_ACTION);
1888         mWifiDiagnostics.dump(fd, pw, args);
1889         dumpIpClient(fd, pw, args);
1890         mWifiConnectivityManager.dump(fd, pw, args);
1891         mWifiHealthMonitor.dump(fd, pw, args);
1892         mWifiInjector.getWakeupController().dump(fd, pw, args);
1893         mLinkProbeManager.dump(fd, pw, args);
1894         mWifiInjector.getWifiLastResortWatchdog().dump(fd, pw, args);
1895     }
1896 
1897     /**
1898      * Trigger message to handle boot completed event.
1899      */
handleBootCompleted()1900     public void handleBootCompleted() {
1901         sendMessage(CMD_BOOT_COMPLETED);
1902     }
1903 
1904     /**
1905      * ******************************************************
1906      * Internal private functions
1907      * ******************************************************
1908      */
1909 
logStateAndMessage(Message message, State state)1910     private void logStateAndMessage(Message message, State state) {
1911         mMessageHandlingStatus = 0;
1912         if (mVerboseLoggingEnabled) {
1913             logd(" " + state.getClass().getSimpleName() + " " + getLogRecString(message));
1914         }
1915     }
1916 
1917     @Override
recordLogRec(Message msg)1918     protected boolean recordLogRec(Message msg) {
1919         switch (msg.what) {
1920             case CMD_RSSI_POLL:
1921                 return mVerboseLoggingEnabled;
1922             default:
1923                 return true;
1924         }
1925     }
1926 
1927     /**
1928      * Return the additional string to be logged by LogRec, default
1929      *
1930      * @param msg that was processed
1931      * @return information to be logged as a String
1932      */
1933     @Override
getLogRecString(Message msg)1934     protected String getLogRecString(Message msg) {
1935         WifiConfiguration config;
1936         Long now;
1937         String report;
1938         String key;
1939         StringBuilder sb = new StringBuilder();
1940         sb.append("screen=").append(mScreenOn ? "on" : "off");
1941         if (mMessageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
1942             sb.append("(").append(mMessageHandlingStatus).append(")");
1943         }
1944         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
1945             sb.append(" uid=" + msg.sendingUid);
1946         }
1947         switch (msg.what) {
1948             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
1949                 sb.append(" ");
1950                 sb.append(Integer.toString(msg.arg1));
1951                 sb.append(" ");
1952                 sb.append(Integer.toString(msg.arg2));
1953                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
1954                 if (stateChangeResult != null) {
1955                     sb.append(stateChangeResult.toString());
1956                 }
1957                 break;
1958             case CMD_CONNECT_NETWORK:
1959             case CMD_SAVE_NETWORK: {
1960                 NetworkUpdateResult result = (NetworkUpdateResult) msg.obj;
1961                 sb.append(" ");
1962                 sb.append(Integer.toString(result.netId));
1963                 sb.append(" ");
1964                 sb.append(Integer.toString(msg.arg2));
1965                 config = mWifiConfigManager.getConfiguredNetwork(result.netId);
1966                 if (config != null) {
1967                     sb.append(" ").append(config.getKey());
1968                     sb.append(" nid=").append(config.networkId);
1969                     if (config.hiddenSSID) {
1970                         sb.append(" hidden");
1971                     }
1972                     if (config.preSharedKey != null
1973                             && !config.preSharedKey.equals("*")) {
1974                         sb.append(" hasPSK");
1975                     }
1976                     if (config.ephemeral) {
1977                         sb.append(" ephemeral");
1978                     }
1979                     sb.append(" cuid=").append(config.creatorUid);
1980                     sb.append(" suid=").append(config.lastUpdateUid);
1981                 }
1982                 break;
1983             }
1984             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
1985                 sb.append(" ");
1986                 sb.append(" timedOut=" + Integer.toString(msg.arg1));
1987                 sb.append(" ");
1988                 sb.append(Integer.toString(msg.arg2));
1989                 String bssid = (String) msg.obj;
1990                 if (bssid != null && bssid.length() > 0) {
1991                     sb.append(" ");
1992                     sb.append(bssid);
1993                 }
1994                 sb.append(" blacklist=" + Boolean.toString(mDidBlackListBSSID));
1995                 break;
1996             case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
1997             case WifiMonitor.NETWORK_CONNECTION_EVENT:
1998                 sb.append(" ");
1999                 sb.append(Integer.toString(msg.arg1));
2000                 sb.append(" ");
2001                 sb.append(Integer.toString(msg.arg2));
2002                 sb.append(" ").append(mLastBssid);
2003                 sb.append(" nid=").append(mLastNetworkId);
2004                 config = getCurrentWifiConfiguration();
2005                 if (config != null) {
2006                     sb.append(" ").append(config.getKey());
2007                 }
2008                 key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2009                 if (key != null) {
2010                     sb.append(" last=").append(key);
2011                 }
2012                 break;
2013             case WifiMonitor.TARGET_BSSID_EVENT:
2014             case WifiMonitor.ASSOCIATED_BSSID_EVENT:
2015                 sb.append(" ");
2016                 sb.append(Integer.toString(msg.arg1));
2017                 sb.append(" ");
2018                 sb.append(Integer.toString(msg.arg2));
2019                 if (msg.obj != null) {
2020                     sb.append(" BSSID=").append((String) msg.obj);
2021                 }
2022                 if (mTargetBssid != null) {
2023                     sb.append(" Target=").append(mTargetBssid);
2024                 }
2025                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2026                 break;
2027             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2028                 if (msg.obj != null) {
2029                     sb.append(" ").append((String) msg.obj);
2030                 }
2031                 sb.append(" nid=").append(msg.arg1);
2032                 sb.append(" reason=").append(msg.arg2);
2033                 if (mLastBssid != null) {
2034                     sb.append(" lastbssid=").append(mLastBssid);
2035                 }
2036                 if (mWifiInfo.getFrequency() != -1) {
2037                     sb.append(" freq=").append(mWifiInfo.getFrequency());
2038                     sb.append(" rssi=").append(mWifiInfo.getRssi());
2039                 }
2040                 break;
2041             case CMD_RSSI_POLL:
2042             case CMD_ONESHOT_RSSI_POLL:
2043             case CMD_UNWANTED_NETWORK:
2044                 sb.append(" ");
2045                 sb.append(Integer.toString(msg.arg1));
2046                 sb.append(" ");
2047                 sb.append(Integer.toString(msg.arg2));
2048                 if (mWifiInfo.getSSID() != null) {
2049                     if (mWifiInfo.getSSID() != null) {
2050                         sb.append(" ").append(mWifiInfo.getSSID());
2051                     }
2052                 }
2053                 if (mWifiInfo.getBSSID() != null) {
2054                     sb.append(" ").append(mWifiInfo.getBSSID());
2055                 }
2056                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2057                 sb.append(" f=").append(mWifiInfo.getFrequency());
2058                 sb.append(" sc=").append(mWifiInfo.getScore());
2059                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2060                 sb.append(String.format(" tx=%.1f,", mWifiInfo.getSuccessfulTxPacketsPerSecond()));
2061                 sb.append(String.format(" %.1f,", mWifiInfo.getRetriedTxPacketsPerSecond()));
2062                 sb.append(String.format(" %.1f ", mWifiInfo.getLostTxPacketsPerSecond()));
2063                 sb.append(String.format(" rx=%.1f", mWifiInfo.getSuccessfulRxPacketsPerSecond()));
2064                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2065                 report = reportOnTime();
2066                 if (report != null) {
2067                     sb.append(" ").append(report);
2068                 }
2069                 sb.append(String.format(" score=%d", mWifiInfo.getScore()));
2070                 break;
2071             case CMD_START_CONNECT:
2072                 sb.append(" ");
2073                 sb.append(Integer.toString(msg.arg1));
2074                 sb.append(" ");
2075                 sb.append(Integer.toString(msg.arg2));
2076                 config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2077                 if (config != null) {
2078                     sb.append(" targetConfigKey=").append(config.getKey());
2079                     sb.append(" BSSID=" + config.BSSID);
2080                 }
2081                 if (mTargetBssid != null) {
2082                     sb.append(" targetBssid=").append(mTargetBssid);
2083                 }
2084                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2085                 config = getCurrentWifiConfiguration();
2086                 if (config != null) {
2087                     sb.append(" currentConfigKey=").append(config.getKey());
2088                 }
2089                 break;
2090             case CMD_START_ROAM:
2091                 sb.append(" ");
2092                 sb.append(Integer.toString(msg.arg1));
2093                 sb.append(" ");
2094                 sb.append(Integer.toString(msg.arg2));
2095                 ScanResult result = (ScanResult) msg.obj;
2096                 if (result != null) {
2097                     now = mClock.getWallClockMillis();
2098                     sb.append(" bssid=").append(result.BSSID);
2099                     sb.append(" rssi=").append(result.level);
2100                     sb.append(" freq=").append(result.frequency);
2101                     if (result.seen > 0 && result.seen < now) {
2102                         sb.append(" seen=").append(now - result.seen);
2103                     } else {
2104                         // Somehow the timestamp for this scan result is inconsistent
2105                         sb.append(" !seen=").append(result.seen);
2106                     }
2107                 }
2108                 if (mTargetBssid != null) {
2109                     sb.append(" ").append(mTargetBssid);
2110                 }
2111                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2112                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
2113                 break;
2114             case CMD_PRE_DHCP_ACTION:
2115                 sb.append(" ");
2116                 sb.append(Integer.toString(msg.arg1));
2117                 sb.append(" ");
2118                 sb.append(Integer.toString(msg.arg2));
2119                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
2120                 sb.append(",").append(mWifiInfo.txBad);
2121                 sb.append(",").append(mWifiInfo.txRetries);
2122                 break;
2123             case CMD_POST_DHCP_ACTION:
2124                 if (mLinkProperties != null) {
2125                     sb.append(" ");
2126                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2127                 }
2128                 break;
2129             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2130                 sb.append(" ");
2131                 sb.append(Integer.toString(msg.arg1));
2132                 sb.append(" ");
2133                 sb.append(Integer.toString(msg.arg2));
2134                 if (msg.obj != null) {
2135                     NetworkInfo info = (NetworkInfo) msg.obj;
2136                     NetworkInfo.State state = info.getState();
2137                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
2138                     if (state != null) {
2139                         sb.append(" st=").append(state);
2140                     }
2141                     if (detailedState != null) {
2142                         sb.append("/").append(detailedState);
2143                     }
2144                 }
2145                 break;
2146             case CMD_IP_CONFIGURATION_LOST:
2147                 int count = -1;
2148                 WifiConfiguration c = getCurrentWifiConfiguration();
2149                 if (c != null) {
2150                     count = c.getNetworkSelectionStatus().getDisableReasonCounter(
2151                             WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
2152                 }
2153                 sb.append(" ");
2154                 sb.append(Integer.toString(msg.arg1));
2155                 sb.append(" ");
2156                 sb.append(Integer.toString(msg.arg2));
2157                 sb.append(" failures: ");
2158                 sb.append(Integer.toString(count));
2159                 sb.append("/");
2160                 sb.append(Integer.toString(mFacade.getIntegerSetting(
2161                         mContext, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 0)));
2162                 if (mWifiInfo.getBSSID() != null) {
2163                     sb.append(" ").append(mWifiInfo.getBSSID());
2164                 }
2165                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2166                 break;
2167             case CMD_UPDATE_LINKPROPERTIES:
2168                 sb.append(" ");
2169                 sb.append(Integer.toString(msg.arg1));
2170                 sb.append(" ");
2171                 sb.append(Integer.toString(msg.arg2));
2172                 if (mLinkProperties != null) {
2173                     sb.append(" ");
2174                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2175                 }
2176                 break;
2177             case CMD_IP_REACHABILITY_LOST:
2178                 if (msg.obj != null) {
2179                     sb.append(" ").append((String) msg.obj);
2180                 }
2181                 break;
2182             case CMD_INSTALL_PACKET_FILTER:
2183                 sb.append(" len=" + ((byte[]) msg.obj).length);
2184                 break;
2185             case CMD_SET_FALLBACK_PACKET_FILTERING:
2186                 sb.append(" enabled=" + (boolean) msg.obj);
2187                 break;
2188             case CMD_ROAM_WATCHDOG_TIMER:
2189                 sb.append(" ");
2190                 sb.append(Integer.toString(msg.arg1));
2191                 sb.append(" ");
2192                 sb.append(Integer.toString(msg.arg2));
2193                 sb.append(" cur=").append(mRoamWatchdogCount);
2194                 break;
2195             case CMD_DISCONNECTING_WATCHDOG_TIMER:
2196                 sb.append(" ");
2197                 sb.append(Integer.toString(msg.arg1));
2198                 sb.append(" ");
2199                 sb.append(Integer.toString(msg.arg2));
2200                 sb.append(" cur=").append(mDisconnectingWatchdogCount);
2201                 break;
2202             case CMD_START_RSSI_MONITORING_OFFLOAD:
2203             case CMD_STOP_RSSI_MONITORING_OFFLOAD:
2204             case CMD_RSSI_THRESHOLD_BREACHED:
2205                 sb.append(" rssi=");
2206                 sb.append(Integer.toString(msg.arg1));
2207                 sb.append(" thresholds=");
2208                 sb.append(Arrays.toString(mRssiRanges));
2209                 break;
2210             case CMD_IPV4_PROVISIONING_SUCCESS:
2211                 sb.append(" ");
2212                 sb.append(/* DhcpResultsParcelable */ msg.obj);
2213                 break;
2214             case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE:
2215                 BtmFrameData frameData = (BtmFrameData) msg.obj;
2216                 if (frameData != null) {
2217                     sb.append(" ").append(frameData.toString());
2218                 }
2219                 break;
2220             default:
2221                 sb.append(" ");
2222                 sb.append(Integer.toString(msg.arg1));
2223                 sb.append(" ");
2224                 sb.append(Integer.toString(msg.arg2));
2225                 break;
2226         }
2227 
2228         return sb.toString();
2229     }
2230 
2231     @Override
getWhatToString(int what)2232     protected String getWhatToString(int what) {
2233         String s = sGetWhatToString.get(what);
2234         if (s != null) {
2235             return s;
2236         }
2237         switch (what) {
2238             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
2239                 s = "CMD_CHANNEL_HALF_CONNECTED";
2240                 break;
2241             case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
2242                 s = "CMD_CHANNEL_DISCONNECTED";
2243                 break;
2244             case CMD_CONNECT_NETWORK:
2245                 s = "CMD_CONNECT_NETWORK";
2246                 break;
2247             case CMD_SAVE_NETWORK:
2248                 s = "CMD_SAVE_NETWORK";
2249                 break;
2250             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2251                 s = "SUPPLICANT_STATE_CHANGE_EVENT";
2252                 break;
2253             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2254                 s = "AUTHENTICATION_FAILURE_EVENT";
2255                 break;
2256             case WifiMonitor.SUP_REQUEST_IDENTITY:
2257                 s = "SUP_REQUEST_IDENTITY";
2258                 break;
2259             case WifiMonitor.NETWORK_CONNECTION_EVENT:
2260                 s = "NETWORK_CONNECTION_EVENT";
2261                 break;
2262             case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
2263                 s = "FILS_NETWORK_CONNECTION_EVENT";
2264                 break;
2265             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2266                 s = "NETWORK_DISCONNECTION_EVENT";
2267                 break;
2268             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2269                 s = "ASSOCIATION_REJECTION_EVENT";
2270                 break;
2271             case WifiMonitor.ANQP_DONE_EVENT:
2272                 s = "ANQP_DONE_EVENT";
2273                 break;
2274             case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
2275                 s = "RX_HS20_ANQP_ICON_EVENT";
2276                 break;
2277             case WifiMonitor.GAS_QUERY_DONE_EVENT:
2278                 s = "GAS_QUERY_DONE_EVENT";
2279                 break;
2280             case WifiMonitor.HS20_REMEDIATION_EVENT:
2281                 s = "HS20_REMEDIATION_EVENT";
2282                 break;
2283             case WifiMonitor.GAS_QUERY_START_EVENT:
2284                 s = "GAS_QUERY_START_EVENT";
2285                 break;
2286             case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE:
2287                 s = "MBO_OCE_BSS_TM_HANDLING_DONE";
2288                 break;
2289             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
2290                 s = "GROUP_CREATING_TIMED_OUT";
2291                 break;
2292             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2293                 s = "P2P_CONNECTION_CHANGED";
2294                 break;
2295             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
2296                 s = "DISCONNECT_WIFI_REQUEST";
2297                 break;
2298             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
2299                 s = "DISCONNECT_WIFI_RESPONSE";
2300                 break;
2301             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
2302                 s = "SET_MIRACAST_MODE";
2303                 break;
2304             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
2305                 s = "BLOCK_DISCOVERY";
2306                 break;
2307             default:
2308                 s = "what:" + Integer.toString(what);
2309                 break;
2310         }
2311         return s;
2312     }
2313 
handleScreenStateChanged(boolean screenOn)2314     private void handleScreenStateChanged(boolean screenOn) {
2315         mScreenOn = screenOn;
2316         if (mVerboseLoggingEnabled) {
2317             logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
2318                     + " mSuspendOptimizationsEnabled="
2319                     + mContext.getResources().getBoolean(
2320                             R.bool.config_wifiSuspendOptimizationsEnabled)
2321                     + " state " + getCurrentState().getName());
2322         }
2323         enableRssiPolling(screenOn);
2324         if (mContext.getResources().getBoolean(R.bool.config_wifiSuspendOptimizationsEnabled)) {
2325             int shouldReleaseWakeLock = 0;
2326             if (screenOn) {
2327                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, shouldReleaseWakeLock);
2328             } else {
2329                 if (isConnected()) {
2330                     // Allow 2s for suspend optimizations to be set
2331                     mSuspendWakeLock.acquire(2000);
2332                     shouldReleaseWakeLock = 1;
2333                 }
2334                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, shouldReleaseWakeLock);
2335             }
2336         }
2337 
2338         getWifiLinkLayerStats();
2339         mOnTimeScreenStateChange = mOnTime;
2340         mLastScreenStateChangeTimeStamp = mLastLinkLayerStatsUpdate;
2341 
2342         mWifiMetrics.setScreenState(screenOn);
2343 
2344         mWifiConnectivityManager.handleScreenStateChanged(screenOn);
2345         mNetworkFactory.handleScreenStateChanged(screenOn);
2346 
2347         WifiLockManager wifiLockManager = mWifiInjector.getWifiLockManager();
2348         if (wifiLockManager == null) {
2349             Log.w(TAG, "WifiLockManager not initialized, skipping screen state notification");
2350         } else {
2351             wifiLockManager.handleScreenStateChanged(screenOn);
2352         }
2353 
2354         mSarManager.handleScreenStateChanged(screenOn);
2355 
2356         if (mVerboseLoggingEnabled) log("handleScreenStateChanged Exit: " + screenOn);
2357     }
2358 
checkAndSetConnectivityInstance()2359     private boolean checkAndSetConnectivityInstance() {
2360         if (mCm == null) {
2361             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
2362         }
2363         if (mCm == null) {
2364             Log.e(TAG, "Cannot retrieve connectivity service");
2365             return false;
2366         }
2367         return true;
2368     }
2369 
setSuspendOptimizationsNative(int reason, boolean enabled)2370     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
2371         if (mVerboseLoggingEnabled) {
2372             log("setSuspendOptimizationsNative: " + reason + " " + enabled
2373                     + " -want " + mContext.getResources().getBoolean(
2374                             R.bool.config_wifiSuspendOptimizationsEnabled)
2375                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2376                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2377                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2378                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2379         }
2380         //mWifiNative.setSuspendOptimizations(enabled);
2381 
2382         if (enabled) {
2383             mSuspendOptNeedsDisabled &= ~reason;
2384             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
2385             if (mSuspendOptNeedsDisabled == 0
2386                     && mContext.getResources().getBoolean(
2387                             R.bool.config_wifiSuspendOptimizationsEnabled)) {
2388                 if (mVerboseLoggingEnabled) {
2389                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
2390                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2391                             + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2392                             + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2393                             + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2394                 }
2395                 mWifiNative.setSuspendOptimizations(mInterfaceName, true);
2396             }
2397         } else {
2398             mSuspendOptNeedsDisabled |= reason;
2399             mWifiNative.setSuspendOptimizations(mInterfaceName, false);
2400         }
2401     }
2402 
2403     /**
2404      * Makes a record of the user intent about suspend optimizations.
2405      */
setSuspendOptimizations(int reason, boolean enabled)2406     private void setSuspendOptimizations(int reason, boolean enabled) {
2407         if (mVerboseLoggingEnabled) log("setSuspendOptimizations: " + reason + " " + enabled);
2408         if (enabled) {
2409             mSuspendOptNeedsDisabled &= ~reason;
2410         } else {
2411             mSuspendOptNeedsDisabled |= reason;
2412         }
2413         if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2414     }
2415 
2416     /*
2417      * Fetch RSSI, linkspeed, and frequency on current connection
2418      */
fetchRssiLinkSpeedAndFrequencyNative()2419     private void fetchRssiLinkSpeedAndFrequencyNative() {
2420         WifiNl80211Manager.SignalPollResult pollResult = mWifiNative.signalPoll(mInterfaceName);
2421         if (pollResult == null) {
2422             return;
2423         }
2424 
2425         int newRssi = pollResult.currentRssiDbm;
2426         int newTxLinkSpeed = pollResult.txBitrateMbps;
2427         int newFrequency = pollResult.associationFrequencyMHz;
2428         int newRxLinkSpeed = pollResult.rxBitrateMbps;
2429 
2430         if (mVerboseLoggingEnabled) {
2431             logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" + newRssi
2432                     + " TxLinkspeed=" + newTxLinkSpeed + " freq=" + newFrequency
2433                     + " RxLinkSpeed=" + newRxLinkSpeed);
2434         }
2435 
2436         if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
2437             /*
2438              * Positive RSSI is possible when devices are close(~0m apart) to each other.
2439              * And there are some driver/firmware implementation, where they avoid
2440              * reporting large negative rssi values by adding 256.
2441              * so adjust the valid rssi reports for such implementations.
2442              */
2443             if (newRssi > (WifiInfo.INVALID_RSSI + 256)) {
2444                 Log.wtf(TAG, "Error! +ve value RSSI: " + newRssi);
2445                 newRssi -= 256;
2446             }
2447             mWifiInfo.setRssi(newRssi);
2448             /*
2449              * Rather then sending the raw RSSI out every time it
2450              * changes, we precalculate the signal level that would
2451              * be displayed in the status bar, and only send the
2452              * broadcast if that much more coarse-grained number
2453              * changes. This cuts down greatly on the number of
2454              * broadcasts, at the cost of not informing others
2455              * interested in RSSI of all the changes in signal
2456              * level.
2457              */
2458             int newSignalLevel = RssiUtil.calculateSignalLevel(mContext, newRssi);
2459             if (newSignalLevel != mLastSignalLevel) {
2460                 updateCapabilities();
2461                 sendRssiChangeBroadcast(newRssi);
2462             }
2463             mLastSignalLevel = newSignalLevel;
2464         } else {
2465             mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
2466             updateCapabilities();
2467         }
2468         /*
2469          * set Tx link speed only if it is valid
2470          */
2471         if (newTxLinkSpeed > 0) {
2472             mWifiInfo.setLinkSpeed(newTxLinkSpeed);
2473             mWifiInfo.setTxLinkSpeedMbps(newTxLinkSpeed);
2474         }
2475         /*
2476          * set Rx link speed only if it is valid
2477          */
2478         if (newRxLinkSpeed > 0) {
2479             mWifiInfo.setRxLinkSpeedMbps(newRxLinkSpeed);
2480         }
2481         if (newFrequency > 0) {
2482             mWifiInfo.setFrequency(newFrequency);
2483         }
2484         mWifiConfigManager.updateScanDetailCacheFromWifiInfo(mWifiInfo);
2485         /*
2486          * Increment various performance metrics
2487          */
2488         mWifiMetrics.handlePollResult(mWifiInfo);
2489     }
2490 
2491     // Polling has completed, hence we won't have a score anymore
cleanWifiScore()2492     private void cleanWifiScore() {
2493         mWifiInfo.setLostTxPacketsPerSecond(0);
2494         mWifiInfo.setSuccessfulTxPacketsPerSecond(0);
2495         mWifiInfo.setRetriedTxPacketsRate(0);
2496         mWifiInfo.setSuccessfulRxPacketsPerSecond(0);
2497         mWifiScoreReport.reset();
2498         mLastLinkLayerStats = null;
2499     }
2500 
updateLinkProperties(LinkProperties newLp)2501     private void updateLinkProperties(LinkProperties newLp) {
2502         if (mVerboseLoggingEnabled) {
2503             log("Link configuration changed for netId: " + mLastNetworkId
2504                     + " old: " + mLinkProperties + " new: " + newLp);
2505         }
2506         // We own this instance of LinkProperties because IpClient passes us a copy.
2507         mLinkProperties = newLp;
2508         if (mNetworkAgent != null) {
2509             mNetworkAgent.sendLinkProperties(mLinkProperties);
2510         }
2511 
2512         if (mNetworkAgentState == DetailedState.CONNECTED) {
2513             // If anything has changed and we're already connected, send out a notification.
2514             // TODO: Update all callers to use NetworkCallbacks and delete this.
2515             sendLinkConfigurationChangedBroadcast();
2516         }
2517 
2518         if (mVerboseLoggingEnabled) {
2519             StringBuilder sb = new StringBuilder();
2520             sb.append("updateLinkProperties nid: " + mLastNetworkId);
2521             sb.append(" state: " + mNetworkAgentState);
2522 
2523             if (mLinkProperties != null) {
2524                 sb.append(" ");
2525                 sb.append(getLinkPropertiesSummary(mLinkProperties));
2526             }
2527             logd(sb.toString());
2528         }
2529     }
2530 
2531     /**
2532      * Clears all our link properties.
2533      */
clearLinkProperties()2534     private void clearLinkProperties() {
2535         // Clear the link properties obtained from DHCP. The only caller of this
2536         // function has already called IpClient#stop(), which clears its state.
2537         synchronized (mDhcpResultsParcelableLock) {
2538             mDhcpResultsParcelable = new DhcpResultsParcelable();
2539         }
2540 
2541         // Now clear the merged link properties.
2542         mLinkProperties.clear();
2543         if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
2544     }
2545 
sendRssiChangeBroadcast(final int newRssi)2546     private void sendRssiChangeBroadcast(final int newRssi) {
2547         mBatteryStatsManager.reportWifiRssiChanged(newRssi);
2548         WifiStatsLog.write(WifiStatsLog.WIFI_SIGNAL_STRENGTH_CHANGED,
2549                 RssiUtil.calculateSignalLevel(mContext, newRssi));
2550 
2551         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
2552         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2553         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
2554         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
2555                 android.Manifest.permission.ACCESS_WIFI_STATE);
2556     }
2557 
sendLinkConfigurationChangedBroadcast()2558     private void sendLinkConfigurationChangedBroadcast() {
2559         Intent intent = new Intent(WifiManager.ACTION_LINK_CONFIGURATION_CHANGED);
2560         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2561         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
2562         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2563     }
2564 
2565     /**
2566      * Helper method used to send state about supplicant - This is NOT information about the current
2567      * wifi connection state.
2568      *
2569      * TODO: b/79504296 This broadcast has been deprecated and should be removed
2570      */
sendSupplicantConnectionChangedBroadcast(boolean connected)2571     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
2572         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
2573         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2574         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
2575         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2576     }
2577 
2578     /**
2579      * Record the detailed state of a network.
2580      *
2581      * @param state the new {@code DetailedState}
2582      */
sendNetworkChangeBroadcast(NetworkInfo.DetailedState state)2583     private void sendNetworkChangeBroadcast(NetworkInfo.DetailedState state) {
2584         boolean hidden = false;
2585 
2586         if (mIsAutoRoaming) {
2587             // There is generally a confusion in the system about colluding
2588             // WiFi Layer 2 state (as reported by supplicant) and the Network state
2589             // which leads to multiple confusion.
2590             //
2591             // If link is roaming, we already have an IP address
2592             // as well we were connected and are doing L2 cycles of
2593             // reconnecting or renewing IP address to check that we still have it
2594             // This L2 link flapping should not be reflected into the Network state
2595             // which is the state of the WiFi Network visible to Layer 3 and applications
2596             // Note that once roaming is completed, we will
2597             // set the Network state to where it should be, or leave it as unchanged
2598             //
2599             hidden = true;
2600         }
2601         if (mVerboseLoggingEnabled) {
2602             log("setDetailed state, old ="
2603                     + mNetworkAgentState + " and new state=" + state
2604                     + " hidden=" + hidden);
2605         }
2606         if (hidden || state == mNetworkAgentState) return;
2607         mNetworkAgentState = state;
2608 
2609         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
2610         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2611         NetworkInfo networkInfo = makeNetworkInfo();
2612         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
2613         //TODO(b/69974497) This should be non-sticky, but settings needs fixing first.
2614         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2615     }
2616 
makeNetworkInfo()2617     private NetworkInfo makeNetworkInfo() {
2618         final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
2619         ni.setDetailedState(mNetworkAgentState, null, null);
2620         return ni;
2621     }
2622 
handleSupplicantStateChange(Message message)2623     private SupplicantState handleSupplicantStateChange(Message message) {
2624         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2625         SupplicantState state = stateChangeResult.state;
2626         mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, state);
2627         // Supplicant state change
2628         // [31-13] Reserved for future use
2629         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
2630         // 50023 supplicant_state_changed (custom|1|5)
2631         mWifiInfo.setSupplicantState(state);
2632         // Network id and SSID are only valid when we start connecting
2633         if (SupplicantState.isConnecting(state)) {
2634             mWifiInfo.setNetworkId(stateChangeResult.networkId);
2635             mWifiInfo.setBSSID(stateChangeResult.BSSID);
2636             mWifiInfo.setSSID(stateChangeResult.wifiSsid);
2637             if (state == SupplicantState.ASSOCIATED) {
2638                 updateWifiInfoAfterAssociation();
2639             }
2640         } else {
2641             // Reset parameters according to WifiInfo.reset()
2642             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2643             mWifiInfo.setBSSID(null);
2644             mWifiInfo.setSSID(null);
2645             mWifiInfo.setWifiStandard(ScanResult.WIFI_STANDARD_UNKNOWN);
2646         }
2647         updateLayer2Information();
2648         // SSID might have been updated, so call updateCapabilities
2649         updateCapabilities();
2650 
2651         WifiConfiguration config = getCurrentWifiConfiguration();
2652         if (config == null) {
2653             // If not connected, this should be non-null.
2654             config = getTargetWifiConfiguration();
2655         }
2656         if (config != null && config.networkId == mWifiInfo.getNetworkId()) {
2657             mWifiInfo.setEphemeral(config.ephemeral);
2658             mWifiInfo.setTrusted(config.trusted);
2659             mWifiInfo.setOsuAp(config.osu);
2660             if (config.fromWifiNetworkSpecifier || config.fromWifiNetworkSuggestion) {
2661                 mWifiInfo.setRequestingPackageName(config.creatorName);
2662             }
2663 
2664             // Set meteredHint if scan result says network is expensive
2665             ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
2666                     config.networkId);
2667             if (scanDetailCache != null) {
2668                 ScanDetail scanDetail = scanDetailCache.getScanDetail(stateChangeResult.BSSID);
2669                 if (scanDetail != null) {
2670                     mWifiInfo.setFrequency(scanDetail.getScanResult().frequency);
2671                     NetworkDetail networkDetail = scanDetail.getNetworkDetail();
2672                     if (networkDetail != null
2673                             && networkDetail.getAnt() == NetworkDetail.Ant.ChargeablePublic) {
2674                         mWifiInfo.setMeteredHint(true);
2675                     }
2676                 }
2677             }
2678         }
2679         mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
2680         return state;
2681     }
2682 
updateWifiInfoAfterAssociation()2683     private void updateWifiInfoAfterAssociation() {
2684         WifiNative.ConnectionCapabilities capabilities =
2685                 mWifiNative.getConnectionCapabilities(mInterfaceName);
2686         ThroughputPredictor throughputPredictor = mWifiInjector.getThroughputPredictor();
2687         int maxTxLinkSpeedMbps = throughputPredictor.predictMaxTxThroughput(capabilities);
2688         int maxRxLinkSpeedMbps = throughputPredictor.predictMaxRxThroughput(capabilities);
2689         mWifiInfo.setWifiStandard(capabilities.wifiStandard);
2690         mWifiInfo.setMaxSupportedTxLinkSpeedMbps(maxTxLinkSpeedMbps);
2691         mWifiInfo.setMaxSupportedRxLinkSpeedMbps(maxRxLinkSpeedMbps);
2692         mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(
2693                 maxTxLinkSpeedMbps, maxRxLinkSpeedMbps);
2694         mWifiDataStall.setConnectionCapabilities(capabilities);
2695         if (mVerboseLoggingEnabled) {
2696             StringBuilder sb = new StringBuilder();
2697             logd(sb.append("WifiStandard: ").append(capabilities.wifiStandard)
2698                     .append(" maxTxSpeed: ").append(maxTxLinkSpeedMbps)
2699                     .append(" maxRxSpeed: ").append(maxRxLinkSpeedMbps)
2700                     .toString());
2701         }
2702     }
2703 
2704     /**
2705      * Tells IpClient what BSSID, L2Key and GroupHint to use for IpMemoryStore.
2706      */
updateLayer2Information()2707     private void updateLayer2Information() {
2708         if (mIpClient != null) {
2709             Pair<String, String> p = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
2710             if (!p.equals(mLastL2KeyAndGroupHint)) {
2711                 final MacAddress lastBssid = getCurrentBssid();
2712                 final Layer2Information l2Information = new Layer2Information(
2713                         p.first, p.second, lastBssid);
2714                 // Update current BSSID on IpClient side whenever l2Key and groupHint
2715                 // pair changes (i.e. the initial connection establishment or L2 roaming
2716                 // happened). If we have COMPLETED the roaming to a different BSSID, start
2717                 // doing DNAv4/DNAv6 -style probing for on-link neighbors of interest (e.g.
2718                 // routers/DNS servers/default gateway).
2719                 if (mIpClient.updateLayer2Information(l2Information)) {
2720                     mLastL2KeyAndGroupHint = p;
2721                 } else {
2722                     mLastL2KeyAndGroupHint = null;
2723                 }
2724             }
2725         }
2726     }
2727     private @Nullable Pair<String, String> mLastL2KeyAndGroupHint = null;
2728 
2729     /**
2730      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
2731      * using the interface, stopping DHCP & disabling interface
2732      */
handleNetworkDisconnect()2733     private void handleNetworkDisconnect() {
2734         if (mVerboseLoggingEnabled) {
2735             log("handleNetworkDisconnect:"
2736                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2737                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2738                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2739                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2740         }
2741 
2742         WifiConfiguration wifiConfig = getCurrentWifiConfiguration();
2743         if (wifiConfig != null) {
2744             ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromWifiConfiguration(wifiConfig);
2745             mWifiInjector.getWakeupController().setLastDisconnectInfo(matchInfo);
2746             mWifiNetworkSuggestionsManager.handleDisconnect(wifiConfig, getCurrentBSSID());
2747         }
2748         stopRssiMonitoringOffload();
2749 
2750         clearTargetBssid("handleNetworkDisconnect");
2751 
2752         // Don't stop DHCP if Fils connection is in progress.
2753         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
2754                 && mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID
2755                 && mLastNetworkId != mTargetNetworkId && mIpClientWithPreConnection) {
2756             if (mVerboseLoggingEnabled) {
2757                 log("handleNetworkDisconnect: Don't stop IpClient as fils connection in progress: "
2758                         + " mLastNetworkId: " + mLastNetworkId
2759                         + " mTargetNetworkId" + mTargetNetworkId);
2760             }
2761         } else {
2762             stopDhcpSetup();
2763         }
2764 
2765         mWifiScoreReport.stopConnectedNetworkScorer();
2766         /* Reset data structures */
2767         mWifiScoreReport.reset();
2768         mWifiInfo.reset();
2769         /* Reset roaming parameters */
2770         mIsAutoRoaming = false;
2771 
2772         sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
2773         if (mNetworkAgent != null) {
2774             mNetworkAgent.unregister();
2775             mNetworkAgent = null;
2776         }
2777 
2778         /* Clear network properties */
2779         clearLinkProperties();
2780 
2781         mLastBssid = null;
2782         mLastLinkLayerStats = null;
2783         registerDisconnected();
2784         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2785         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
2786         mLastSimBasedConnectionCarrierName = null;
2787         checkAbnormalDisconnectionAndTakeBugReport();
2788         mWifiScoreCard.resetConnectionState();
2789         mWifiDataStall.reset();
2790         updateLayer2Information();
2791     }
2792 
handlePreDhcpSetup()2793     void handlePreDhcpSetup() {
2794         if (!mBluetoothConnectionActive) {
2795             /*
2796              * There are problems setting the Wi-Fi driver's power
2797              * mode to active when bluetooth coexistence mode is
2798              * enabled or sense.
2799              * <p>
2800              * We set Wi-Fi to active mode when
2801              * obtaining an IP address because we've found
2802              * compatibility issues with some routers with low power
2803              * mode.
2804              * <p>
2805              * In order for this active power mode to properly be set,
2806              * we disable coexistence mode until we're done with
2807              * obtaining an IP address.  One exception is if we
2808              * are currently connected to a headset, since disabling
2809              * coexistence would interrupt that connection.
2810              */
2811             // Disable the coexistence mode
2812             mWifiNative.setBluetoothCoexistenceMode(
2813                     mInterfaceName, WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
2814         }
2815 
2816         // Disable power save and suspend optimizations during DHCP
2817         // Note: The order here is important for now. Brcm driver changes
2818         // power settings when we control suspend mode optimizations.
2819         // TODO: Remove this comment when the driver is fixed.
2820         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
2821         setPowerSave(false);
2822 
2823         // Update link layer stats
2824         getWifiLinkLayerStats();
2825 
2826         if (mWifiP2pChannel != null) {
2827             /* P2p discovery breaks dhcp, shut it down in order to get through this */
2828             Message msg = new Message();
2829             msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
2830             msg.arg1 = WifiP2pServiceImpl.ENABLED;
2831             msg.arg2 = CMD_PRE_DHCP_ACTION_COMPLETE;
2832             mWifiP2pChannel.sendMessage(msg);
2833         } else {
2834             // If the p2p service is not running, we can proceed directly.
2835             sendMessage(CMD_PRE_DHCP_ACTION_COMPLETE);
2836         }
2837     }
2838 
addLayer2PacketsToHlpReq(List<Layer2PacketParcelable> packets)2839     void addLayer2PacketsToHlpReq(List<Layer2PacketParcelable> packets) {
2840         List<Layer2PacketParcelable> mLayer2Packet = packets;
2841         if ((mLayer2Packet != null) && (mLayer2Packet.size() > 0)) {
2842             mWifiNative.flushAllHlp(mInterfaceName);
2843 
2844             for (int j = 0; j < mLayer2Packet.size(); j++) {
2845                 byte [] bytes = mLayer2Packet.get(j).payload;
2846                 byte [] payloadBytes = Arrays.copyOfRange(bytes, 12, bytes.length);
2847                 MacAddress dstAddress = mLayer2Packet.get(j).dstMacAddress;
2848 
2849                 mWifiNative.addHlpReq(mInterfaceName, dstAddress, payloadBytes);
2850             }
2851         }
2852     }
2853 
handlePostDhcpSetup()2854     void handlePostDhcpSetup() {
2855         /* Restore power save and suspend optimizations */
2856         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
2857         setPowerSave(true);
2858 
2859         p2pSendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
2860 
2861         // Set the coexistence mode back to its default value
2862         mWifiNative.setBluetoothCoexistenceMode(
2863                 mInterfaceName, WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
2864     }
2865 
2866     /**
2867      * Set power save mode
2868      *
2869      * @param ps true to enable power save (default behavior)
2870      *           false to disable power save.
2871      * @return true for success, false for failure
2872      */
setPowerSave(boolean ps)2873     public boolean setPowerSave(boolean ps) {
2874         if (mInterfaceName != null) {
2875             if (mVerboseLoggingEnabled) {
2876                 Log.d(TAG, "Setting power save for: " + mInterfaceName + " to: " + ps);
2877             }
2878             mWifiNative.setPowerSave(mInterfaceName, ps);
2879         } else {
2880             Log.e(TAG, "Failed to setPowerSave, interfaceName is null");
2881             return false;
2882         }
2883         return true;
2884     }
2885 
2886     /**
2887      * Set low latency mode
2888      *
2889      * @param enabled true to enable low latency
2890      *                false to disable low latency (default behavior).
2891      * @return true for success, false for failure
2892      */
setLowLatencyMode(boolean enabled)2893     public boolean setLowLatencyMode(boolean enabled) {
2894         if (mVerboseLoggingEnabled) {
2895             Log.d(TAG, "Setting low latency mode to " + enabled);
2896         }
2897         if (!mWifiNative.setLowLatencyMode(enabled)) {
2898             Log.e(TAG, "Failed to setLowLatencyMode");
2899             return false;
2900         }
2901         return true;
2902     }
2903 
2904     @VisibleForTesting
2905     public static final long DIAGS_CONNECT_TIMEOUT_MILLIS = 60 * 1000;
2906     /**
2907      * Inform other components that a new connection attempt is starting.
2908      */
reportConnectionAttemptStart( WifiConfiguration config, String targetBSSID, int roamType)2909     private void reportConnectionAttemptStart(
2910             WifiConfiguration config, String targetBSSID, int roamType) {
2911         int overlapWithLastConnectionMs =
2912                 mWifiMetrics.startConnectionEvent(config, targetBSSID, roamType);
2913         DeviceConfigFacade deviceConfigFacade = mWifiInjector.getDeviceConfigFacade();
2914         if (deviceConfigFacade.isOverlappingConnectionBugreportEnabled()
2915                 && overlapWithLastConnectionMs
2916                 > deviceConfigFacade.getOverlappingConnectionDurationThresholdMs()) {
2917             String bugTitle = "Wi-Fi BugReport";
2918             String bugDetail = "Detect abnormal overlapping connection";
2919             takeBugReport(bugTitle, bugDetail);
2920         }
2921         mWifiDiagnostics.reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_STARTED);
2922         mWrongPasswordNotifier.onNewConnectionAttempt();
2923         removeMessages(CMD_DIAGS_CONNECT_TIMEOUT);
2924         sendMessageDelayed(CMD_DIAGS_CONNECT_TIMEOUT, DIAGS_CONNECT_TIMEOUT_MILLIS);
2925     }
2926 
handleConnectionAttemptEndForDiagnostics(int level2FailureCode)2927     private void handleConnectionAttemptEndForDiagnostics(int level2FailureCode) {
2928         switch (level2FailureCode) {
2929             case WifiMetrics.ConnectionEvent.FAILURE_NONE:
2930                 break;
2931             case WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED:
2932                 // WifiDiagnostics doesn't care about pre-empted connections, or cases
2933                 // where we failed to initiate a connection attempt with supplicant.
2934                 break;
2935             default:
2936                 removeMessages(CMD_DIAGS_CONNECT_TIMEOUT);
2937                 mWifiDiagnostics.reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_FAILED);
2938         }
2939     }
2940 
2941     /**
2942      * Inform other components (WifiMetrics, WifiDiagnostics, WifiConnectivityManager, etc.) that
2943      * the current connection attempt has concluded.
2944      */
reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode, int level2FailureReason)2945     private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode,
2946             int level2FailureReason) {
2947         // if connected, this should be non-null.
2948         WifiConfiguration configuration = getCurrentWifiConfiguration();
2949         if (configuration == null) {
2950             // If not connected, this should be non-null.
2951             configuration = getTargetWifiConfiguration();
2952         }
2953 
2954         String bssid = mLastBssid == null ? mTargetBssid : mLastBssid;
2955         String ssid = mWifiInfo.getSSID();
2956         if (WifiManager.UNKNOWN_SSID.equals(ssid)) {
2957             ssid = getTargetSsid();
2958         }
2959         if (level2FailureCode != WifiMetrics.ConnectionEvent.FAILURE_NONE) {
2960             int blocklistReason = convertToBssidBlocklistMonitorFailureReason(
2961                     level2FailureCode, level2FailureReason);
2962             if (blocklistReason != -1) {
2963                 int networkId = (configuration == null) ? WifiConfiguration.INVALID_NETWORK_ID
2964                         : configuration.networkId;
2965                 int scanRssi = mWifiConfigManager.findScanRssi(networkId,
2966                         mWifiHealthMonitor.getScanRssiValidTimeMs());
2967                 mWifiScoreCard.noteConnectionFailure(mWifiInfo, scanRssi, ssid, blocklistReason);
2968                 checkAbnormalConnectionFailureAndTakeBugReport(ssid);
2969                 boolean isLowRssi = false;
2970                 int sufficientRssi = getSufficientRssi(networkId, bssid);
2971                 if (scanRssi != WifiInfo.INVALID_RSSI && sufficientRssi != WifiInfo.INVALID_RSSI) {
2972                     isLowRssi = scanRssi < sufficientRssi;
2973                 }
2974                 mBssidBlocklistMonitor.handleBssidConnectionFailure(bssid, ssid, blocklistReason,
2975                         isLowRssi);
2976             }
2977         }
2978 
2979         if (configuration != null
2980                 && configuration.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
2981             if (level2FailureCode == WifiMetrics.ConnectionEvent.FAILURE_NONE) {
2982                 mWifiMetrics.incrementNumOfCarrierWifiConnectionSuccess();
2983             } else if (level2FailureCode
2984                             == WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE
2985                     && level2FailureReason
2986                             != WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE) {
2987                 mWifiMetrics.incrementNumOfCarrierWifiConnectionAuthFailure();
2988             } else {
2989                 mWifiMetrics.incrementNumOfCarrierWifiConnectionNonAuthFailure();
2990             }
2991         }
2992 
2993         boolean isAssociationRejection = level2FailureCode
2994                 == WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION;
2995         boolean isAuthenticationFailure = level2FailureCode
2996                 == WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE
2997                 && level2FailureReason != WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD;
2998         if ((isAssociationRejection || isAuthenticationFailure)
2999                 && mWifiConfigManager.isInFlakyRandomizationSsidHotlist(mTargetNetworkId)) {
3000             mConnectionFailureNotifier
3001                     .showFailedToConnectDueToNoRandomizedMacSupportNotification(mTargetNetworkId);
3002         }
3003 
3004         mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode,
3005                 level2FailureReason);
3006         mWifiConnectivityManager.handleConnectionAttemptEnded(level2FailureCode, bssid, ssid);
3007         if (configuration != null) {
3008             mNetworkFactory.handleConnectionAttemptEnded(level2FailureCode, configuration);
3009             mWifiNetworkSuggestionsManager.handleConnectionAttemptEnded(
3010                     level2FailureCode, configuration, getCurrentBSSID());
3011             ScanResult candidate = configuration.getNetworkSelectionStatus().getCandidate();
3012             if (candidate != null && !TextUtils.equals(candidate.BSSID, getCurrentBSSID())) {
3013                 mWifiMetrics.incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware();
3014             }
3015         }
3016         handleConnectionAttemptEndForDiagnostics(level2FailureCode);
3017     }
3018 
3019     /* If this connection attempt fails after 802.1x stage, clear intermediate cached data. */
3020     void clearNetworkCachedDataIfNeeded(WifiConfiguration config, int reason) {
3021         if (config == null) return;
3022 
3023         switch(reason) {
3024             case 14: // MICHAEL_MIC_FAILURE
3025             case 15: // 4WAY_HANDSHAKE_TIMEOUT
3026             case 16: // GROUP_KEY_UPDATE_TIMEOUT
3027             case 17: // IE_IN_4WAY_DIFFERS
3028             case 18: // GROUP_CIPHER_NOT_VALID
3029             case 19: // PAIRWISE_CIPHER_NOT_VALID
3030             case 20: // AKMP_NOT_VALID
3031             case 23: // IEEE_802_1X_AUTH_FAILED
3032             case 24: // CIPHER_SUITE_REJECTED
3033             case 29: // BAD_CIPHER_OR_AKM
3034             case 45: // PEERKEY_MISMATCH
3035             case 49: // INVALID_PMKID
3036                 mWifiNative.removeNetworkCachedData(config.networkId);
3037                 break;
3038             default:
3039                 logi("Keep PMK cache for network disconnection reason " + reason);
3040                 break;
3041         }
3042     }
3043 
3044     /**
3045      * Returns the sufficient RSSI for the frequency that this network is last seen on.
3046      */
3047     private int getSufficientRssi(int networkId, String bssid) {
3048         ScanDetailCache scanDetailCache =
3049                 mWifiConfigManager.getScanDetailCacheForNetwork(networkId);
3050         if (scanDetailCache == null) {
3051             return WifiInfo.INVALID_RSSI;
3052         }
3053         ScanResult scanResult = scanDetailCache.getScanResult(bssid);
3054         if (scanResult == null) {
3055             return WifiInfo.INVALID_RSSI;
3056         }
3057         return mWifiInjector.getScoringParams().getSufficientRssi(scanResult.frequency);
3058     }
3059 
3060     private int convertToBssidBlocklistMonitorFailureReason(
3061             int level2FailureCode, int failureReason) {
3062         switch (level2FailureCode) {
3063             case WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT:
3064                 return BssidBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT;
3065             case WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION:
3066                 if (failureReason == WifiMetricsProto.ConnectionEvent
3067                         .ASSOCIATION_REJECTION_AP_UNABLE_TO_HANDLE_NEW_STA) {
3068                     return BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA;
3069                 }
3070                 return BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION;
3071             case WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE:
3072                 if (failureReason == WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD) {
3073                     return BssidBlocklistMonitor.REASON_WRONG_PASSWORD;
3074                 } else if (failureReason == WifiMetricsProto.ConnectionEvent
3075                         .AUTH_FAILURE_EAP_FAILURE) {
3076                     return BssidBlocklistMonitor.REASON_EAP_FAILURE;
3077                 }
3078                 return BssidBlocklistMonitor.REASON_AUTHENTICATION_FAILURE;
3079             case WifiMetrics.ConnectionEvent.FAILURE_DHCP:
3080                 return BssidBlocklistMonitor.REASON_DHCP_FAILURE;
3081             default:
3082                 return -1;
3083         }
3084     }
3085 
3086     private void handleIPv4Success(DhcpResultsParcelable dhcpResults) {
3087         if (mVerboseLoggingEnabled) {
3088             logd("handleIPv4Success <" + dhcpResults.toString() + ">");
3089             logd("link address " + dhcpResults.baseConfiguration.getIpAddress());
3090         }
3091 
3092         Inet4Address addr;
3093         synchronized (mDhcpResultsParcelableLock) {
3094             mDhcpResultsParcelable = dhcpResults;
3095             addr = (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress();
3096         }
3097 
3098         if (mIsAutoRoaming) {
3099             int previousAddress = mWifiInfo.getIpAddress();
3100             int newAddress = Inet4AddressUtils.inet4AddressToIntHTL(addr);
3101             if (previousAddress != newAddress) {
3102                 logd("handleIPv4Success, roaming and address changed"
3103                         + mWifiInfo + " got: " + addr);
3104             }
3105         }
3106 
3107         mWifiInfo.setInetAddress(addr);
3108 
3109         final WifiConfiguration config = getCurrentWifiConfiguration();
3110         if (config != null) {
3111             mWifiInfo.setEphemeral(config.ephemeral);
3112             mWifiInfo.setTrusted(config.trusted);
3113             mWifiConfigManager.updateRandomizedMacExpireTime(config, dhcpResults.leaseDuration);
3114             mBssidBlocklistMonitor.handleDhcpProvisioningSuccess(mLastBssid, mWifiInfo.getSSID());
3115         }
3116 
3117         // Set meteredHint if DHCP result says network is metered
3118         if (dhcpResults.vendorInfo != null && dhcpResults.vendorInfo.contains("ANDROID_METERED")) {
3119             mWifiInfo.setMeteredHint(true);
3120             mWifiMetrics.addMeteredStat(config, true);
3121         } else {
3122             mWifiMetrics.addMeteredStat(config, false);
3123         }
3124 
3125         updateCapabilities(config);
3126     }
3127 
3128     private void handleSuccessfulIpConfiguration() {
3129         mLastSignalLevel = -1; // Force update of signal strength
3130         WifiConfiguration c = getCurrentWifiConfiguration();
3131         if (c != null) {
3132             // Reset IP failure tracking
3133             c.getNetworkSelectionStatus().clearDisableReasonCounter(
3134                     WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3135 
3136             // Tell the framework whether the newly connected network is trusted or untrusted.
3137             updateCapabilities(c);
3138         }
3139         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
3140     }
3141 
3142     private void handleIPv4Failure() {
3143         // TODO: Move this to provisioning failure, not DHCP failure.
3144         // DHCPv4 failure is expected on an IPv6-only network.
3145         mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_DHCP_FAILURE);
3146         if (mVerboseLoggingEnabled) {
3147             int count = -1;
3148             WifiConfiguration config = getCurrentWifiConfiguration();
3149             if (config != null) {
3150                 count = config.getNetworkSelectionStatus().getDisableReasonCounter(
3151                         WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3152             }
3153             log("DHCP failure count=" + count);
3154         }
3155         reportConnectionAttemptEnd(
3156                 WifiMetrics.ConnectionEvent.FAILURE_DHCP,
3157                 WifiMetricsProto.ConnectionEvent.HLF_DHCP,
3158                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
3159         synchronized (mDhcpResultsParcelableLock) {
3160             mDhcpResultsParcelable = new DhcpResultsParcelable();
3161         }
3162         if (mVerboseLoggingEnabled) {
3163             logd("handleIPv4Failure");
3164         }
3165     }
3166 
3167     private void handleIpConfigurationLost() {
3168         mWifiInfo.setInetAddress(null);
3169         mWifiInfo.setMeteredHint(false);
3170 
3171         mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
3172                 WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3173 
3174         /* DHCP times out after about 30 seconds, we do a
3175          * disconnect thru supplicant, we will let autojoin retry connecting to the network
3176          */
3177         mWifiNative.disconnect(mInterfaceName);
3178     }
3179 
3180     private void handleIpReachabilityLost() {
3181         mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
3182         mWifiInfo.setInetAddress(null);
3183         mWifiInfo.setMeteredHint(false);
3184 
3185         // Disconnect via supplicant, and let autojoin retry connecting to the network.
3186         mWifiNative.disconnect(mInterfaceName);
3187     }
3188 
3189     /*
3190      * Read a MAC address in /proc/arp/table, used by ClientModeImpl
3191      * so as to record MAC address of default gateway.
3192      **/
3193     private String macAddressFromRoute(String ipAddress) {
3194         String macAddress = null;
3195         BufferedReader reader = null;
3196         try {
3197             reader = new BufferedReader(new FileReader("/proc/net/arp"));
3198 
3199             // Skip over the line bearing column titles
3200             String line = reader.readLine();
3201 
3202             while ((line = reader.readLine()) != null) {
3203                 String[] tokens = line.split("[ ]+");
3204                 if (tokens.length < 6) {
3205                     continue;
3206                 }
3207 
3208                 // ARP column format is
3209                 // Address HWType HWAddress Flags Mask IFace
3210                 String ip = tokens[0];
3211                 String mac = tokens[3];
3212 
3213                 if (ipAddress.equals(ip)) {
3214                     macAddress = mac;
3215                     break;
3216                 }
3217             }
3218 
3219             if (macAddress == null) {
3220                 loge("Did not find remoteAddress {" + ipAddress + "} in /proc/net/arp");
3221             }
3222 
3223         } catch (FileNotFoundException e) {
3224             loge("Could not open /proc/net/arp to lookup mac address");
3225         } catch (IOException e) {
3226             loge("Could not read /proc/net/arp to lookup mac address");
3227         } finally {
3228             try {
3229                 if (reader != null) {
3230                     reader.close();
3231                 }
3232             } catch (IOException e) {
3233                 // Do nothing
3234             }
3235         }
3236         return macAddress;
3237 
3238     }
3239 
3240     /**
3241      * Determine if the specified auth failure is considered to be a permanent wrong password
3242      * failure. The criteria for such failure is when wrong password error is detected
3243      * and the network had never been connected before.
3244      *
3245      * For networks that have previously connected successfully, we consider wrong password
3246      * failures to be temporary, to be on the conservative side.  Since this might be the
3247      * case where we are trying to connect to a wrong network (e.g. A network with same SSID
3248      * but different password).
3249      */
3250     private boolean isPermanentWrongPasswordFailure(int networkId, int reasonCode) {
3251         if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD) {
3252             return false;
3253         }
3254         WifiConfiguration network = mWifiConfigManager.getConfiguredNetwork(networkId);
3255         if (network != null && network.getNetworkSelectionStatus().hasEverConnected()) {
3256             return false;
3257         }
3258         return true;
3259     }
3260 
3261     void registerNetworkFactory() {
3262         if (!checkAndSetConnectivityInstance()) return;
3263         mNetworkFactory.register();
3264         mUntrustedNetworkFactory.register();
3265     }
3266 
3267     /**
3268      * ClientModeImpl needs to enable/disable other services when wifi is in client mode.  This
3269      * method allows ClientModeImpl to get these additional system services.
3270      *
3271      * At this time, this method is used to setup variables for P2P service and Wifi Aware.
3272      */
3273     private void getAdditionalWifiServiceInterfaces() {
3274         // First set up Wifi Direct
3275         if (mP2pSupported) {
3276             WifiP2pManager wifiP2pService = mContext.getSystemService(WifiP2pManager.class);
3277 
3278             if (wifiP2pService != null) {
3279                 mWifiP2pChannel = new AsyncChannel();
3280                 mWifiP2pChannel.connect(mContext, getHandler(),
3281                         wifiP2pService.getP2pStateMachineMessenger());
3282             }
3283         }
3284     }
3285 
3286      /**
3287      * Dynamically change the MAC address to use the locally randomized
3288      * MAC address generated for each network.
3289      * @param config WifiConfiguration with mRandomizedMacAddress to change into. If the address
3290      * is masked out or not set, it will generate a new random MAC address.
3291      */
3292     private void configureRandomizedMacAddress(WifiConfiguration config) {
3293         if (config == null) {
3294             Log.e(TAG, "No config to change MAC address to");
3295             return;
3296         }
3297         String currentMacString = mWifiNative.getMacAddress(mInterfaceName);
3298         MacAddress currentMac = currentMacString == null ? null :
3299                 MacAddress.fromString(currentMacString);
3300         MacAddress newMac = mWifiConfigManager.getRandomizedMacAndUpdateIfNeeded(config);
3301         if (!WifiConfiguration.isValidMacAddressForRandomization(newMac)) {
3302             Log.wtf(TAG, "Config generated an invalid MAC address");
3303         } else if (newMac.equals(currentMac)) {
3304             Log.d(TAG, "No changes in MAC address");
3305         } else {
3306             mWifiMetrics.logStaEvent(StaEvent.TYPE_MAC_CHANGE, config);
3307             boolean setMacSuccess =
3308                     mWifiNative.setMacAddress(mInterfaceName, newMac);
3309             if (setMacSuccess) {
3310                 mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, newMac);
3311             }
3312             Log.d(TAG, "ConnectedMacRandomization SSID(" + config.getPrintableSsid()
3313                     + "). setMacAddress(" + newMac.toString() + ") from "
3314                     + currentMacString + " = " + setMacSuccess);
3315         }
3316     }
3317 
3318     /**
3319      * Sets the current MAC to the factory MAC address.
3320      */
3321     private void setCurrentMacToFactoryMac(WifiConfiguration config) {
3322         MacAddress factoryMac = mWifiNative.getFactoryMacAddress(mInterfaceName);
3323         if (factoryMac == null) {
3324             Log.e(TAG, "Fail to set factory MAC address. Factory MAC is null.");
3325             return;
3326         }
3327         String currentMacStr = mWifiNative.getMacAddress(mInterfaceName);
3328         if (!TextUtils.equals(currentMacStr, factoryMac.toString())) {
3329             if (mWifiNative.setMacAddress(mInterfaceName, factoryMac)) {
3330                 mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, factoryMac);
3331                 mWifiMetrics.logStaEvent(StaEvent.TYPE_MAC_CHANGE, config);
3332             } else {
3333                 Log.e(TAG, "Failed to set MAC address to " + "'" + factoryMac.toString() + "'");
3334             }
3335         }
3336     }
3337 
3338     /**
3339      * Helper method to check if Connected MAC Randomization is supported - onDown events are
3340      * skipped if this feature is enabled (b/72459123).
3341      *
3342      * @return boolean true if Connected MAC randomization is supported, false otherwise
3343      */
3344     public boolean isConnectedMacRandomizationEnabled() {
3345         return mContext.getResources().getBoolean(
3346                 R.bool.config_wifi_connected_mac_randomization_supported);
3347     }
3348 
3349     /**
3350      * Helper method allowing ClientModeManager to report an error (interface went down) and trigger
3351      * recovery.
3352      *
3353      * @param reason int indicating the SelfRecovery failure type.
3354      */
3355     public void failureDetected(int reason) {
3356         // report a failure
3357         mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_STA_IFACE_DOWN);
3358     }
3359 
3360     /**
3361      * Helper method to check if WPA2 network upgrade feature is enabled in the framework
3362      *
3363      * @return boolean true if feature is enabled.
3364      */
3365     private boolean isWpa3SaeUpgradeEnabled() {
3366         return mContext.getResources().getBoolean(R.bool.config_wifiSaeUpgradeEnabled);
3367     }
3368 
3369     /**
3370      * Helper method to check if WPA2 network upgrade offload is enabled in the driver/fw
3371      *
3372      * @return boolean true if feature is enabled.
3373      */
3374     private boolean isWpa3SaeUpgradeOffloadEnabled() {
3375         return mContext.getResources().getBoolean(R.bool.config_wifiSaeUpgradeOffloadEnabled);
3376     }
3377 
3378     /********************************************************
3379      * HSM states
3380      *******************************************************/
3381 
3382     class DefaultState extends State {
3383 
3384         @Override
3385         public boolean processMessage(Message message) {
3386             boolean handleStatus = HANDLED;
3387             int callbackIdentifier = -1;
3388             int netId;
3389             boolean ok;
3390 
3391             switch (message.what) {
3392                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
3393                     AsyncChannel ac = (AsyncChannel) message.obj;
3394                     if (ac == mWifiP2pChannel) {
3395                         if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3396                             p2pSendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3397                         } else {
3398                             // TODO: We should probably do some cleanup or attempt a retry
3399                             // b/34283611
3400                             loge("WifiP2pService connection failure, error=" + message.arg1);
3401                         }
3402                     } else {
3403                         loge("got HALF_CONNECTED for unknown channel");
3404                     }
3405                     break;
3406                 }
3407                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
3408                     AsyncChannel ac = (AsyncChannel) message.obj;
3409                     if (ac == mWifiP2pChannel) {
3410                         loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
3411                         //TODO: Re-establish connection to state machine after a delay (b/34283611)
3412                         // mWifiP2pChannel.connect(mContext, getHandler(),
3413                         // mWifiP2pManager.getMessenger());
3414                     }
3415                     break;
3416                 }
3417                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
3418                     // If BT was connected and then turned off, there is no CONNECTION_STATE_CHANGE
3419                     // message. So we need to rely on STATE_CHANGE message to detect on->off
3420                     // transition and update mBluetoothConnectionActive status correctly.
3421                     mBluetoothConnectionActive = mBluetoothConnectionActive
3422                             && message.arg1 != BluetoothAdapter.STATE_OFF;
3423                     mWifiConnectivityManager.setBluetoothConnected(mBluetoothConnectionActive);
3424                     break;
3425                 case CMD_BLUETOOTH_ADAPTER_CONNECTION_STATE_CHANGE:
3426                     // Transition to a non-disconnected state does correctly
3427                     // indicate BT is connected or being connected.
3428                     mBluetoothConnectionActive =
3429                             message.arg1 != BluetoothAdapter.STATE_DISCONNECTED;
3430                     mWifiConnectivityManager.setBluetoothConnected(mBluetoothConnectionActive);
3431                     break;
3432                 case CMD_ENABLE_RSSI_POLL:
3433                     mEnableRssiPolling = (message.arg1 == 1);
3434                     break;
3435                 case CMD_SET_HIGH_PERF_MODE:
3436                     if (message.arg1 == 1) {
3437                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
3438                     } else {
3439                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
3440                     }
3441                     break;
3442                 case CMD_INITIALIZE:
3443                     mWifiNative.initialize();
3444                     break;
3445                 case CMD_BOOT_COMPLETED:
3446                     // get other services that we need to manage
3447                     getAdditionalWifiServiceInterfaces();
3448                     registerNetworkFactory();
3449                     mSarManager.handleBootCompleted();
3450                     break;
3451                 case CMD_SCREEN_STATE_CHANGED:
3452                     handleScreenStateChanged(message.arg1 != 0);
3453                     break;
3454                 case CMD_DISCONNECT:
3455                 case CMD_RECONNECT:
3456                 case CMD_REASSOCIATE:
3457                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3458                 case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
3459                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3460                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3461                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3462                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3463                 case CMD_RSSI_POLL:
3464                 case CMD_ONESHOT_RSSI_POLL:
3465                 case CMD_PRE_DHCP_ACTION:
3466                 case CMD_PRE_DHCP_ACTION_COMPLETE:
3467                 case CMD_POST_DHCP_ACTION:
3468                 case WifiMonitor.SUP_REQUEST_IDENTITY:
3469                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
3470                 case WifiMonitor.TARGET_BSSID_EVENT:
3471                 case CMD_START_CONNECT:
3472                 case CMD_START_ROAM:
3473                 case WifiMonitor.ASSOCIATED_BSSID_EVENT:
3474                 case CMD_UNWANTED_NETWORK:
3475                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
3476                 case CMD_ROAM_WATCHDOG_TIMER:
3477                 case CMD_SET_OPERATIONAL_MODE:
3478                     // using the CMD_SET_OPERATIONAL_MODE (sent at front of queue) to trigger the
3479                     // state transitions performed in setOperationalMode.
3480                     break;
3481                 case CMD_SET_SUSPEND_OPT_ENABLED:
3482                     if (message.arg1 == 1) {
3483                         if (message.arg2 == 1) {
3484                             mSuspendWakeLock.release();
3485                         }
3486                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
3487                     } else {
3488                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
3489                     }
3490                     break;
3491                 case CMD_CONNECT_NETWORK:
3492                     // wifi off, can't connect.
3493                     callbackIdentifier = message.arg2;
3494                     sendActionListenerFailure(callbackIdentifier, WifiManager.BUSY);
3495                     break;
3496                 case CMD_SAVE_NETWORK:
3497                     // wifi off, nothing more to do here.
3498                     callbackIdentifier = message.arg2;
3499                     sendActionListenerSuccess(callbackIdentifier);
3500                     break;
3501                 case CMD_GET_SUPPORTED_FEATURES:
3502                     long featureSet = (mWifiNative.getSupportedFeatureSet(mInterfaceName));
3503                     replyToMessage(message, message.what, Long.valueOf(featureSet));
3504                     break;
3505                 case CMD_GET_LINK_LAYER_STATS:
3506                 case CMD_GET_CURRENT_NETWORK:
3507                     // Not supported hence reply with null message.obj
3508                     replyToMessage(message, message.what, null);
3509                     break;
3510                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
3511                     NetworkInfo info = (NetworkInfo) message.obj;
3512                     mP2pConnected.set(info.isConnected());
3513                     break;
3514                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
3515                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
3516                     replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
3517                     break;
3518                 /* Link configuration (IP address, DNS, ...) changes notified via netlink */
3519                 case CMD_UPDATE_LINKPROPERTIES:
3520                     updateLinkProperties((LinkProperties) message.obj);
3521                     break;
3522                 case CMD_START_SUBSCRIPTION_PROVISIONING:
3523                     replyToMessage(message, message.what, 0);
3524                     break;
3525                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
3526                 case CMD_IP_CONFIGURATION_LOST:
3527                 case CMD_IP_REACHABILITY_LOST:
3528                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3529                     break;
3530                 case CMD_START_IP_PACKET_OFFLOAD:
3531                     /* fall-through */
3532                 case CMD_STOP_IP_PACKET_OFFLOAD:
3533                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF:
3534                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF:
3535                     if (mNetworkAgent != null) {
3536                         mNetworkAgent.sendSocketKeepaliveEvent(message.arg1,
3537                                 SocketKeepalive.ERROR_INVALID_NETWORK);
3538                     }
3539                     break;
3540                 case CMD_START_RSSI_MONITORING_OFFLOAD:
3541                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3542                     break;
3543                 case CMD_STOP_RSSI_MONITORING_OFFLOAD:
3544                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3545                     break;
3546                 case CMD_QUERY_OSU_ICON:
3547                     /* reply with arg1 = 0 - it returns API failure to the calling app
3548                      * (message.what is not looked at)
3549                      */
3550                     replyToMessage(message, message.what);
3551                     break;
3552                 case CMD_RESET_SIM_NETWORKS:
3553                     /* Defer this message until supplicant is started. */
3554                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
3555                     deferMessage(message);
3556                     break;
3557                 case CMD_INSTALL_PACKET_FILTER:
3558                     mWifiNative.installPacketFilter(mInterfaceName, (byte[]) message.obj);
3559                     break;
3560                 case CMD_READ_PACKET_FILTER:
3561                     byte[] data = mWifiNative.readPacketFilter(mInterfaceName);
3562                     if (mIpClient != null) {
3563                         mIpClient.readPacketFilterComplete(data);
3564                     }
3565                     break;
3566                 case CMD_SET_FALLBACK_PACKET_FILTERING:
3567                     if ((boolean) message.obj) {
3568                         mWifiNative.startFilteringMulticastV4Packets(mInterfaceName);
3569                     } else {
3570                         mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName);
3571                     }
3572                     break;
3573                 case CMD_DIAGS_CONNECT_TIMEOUT:
3574                     mWifiDiagnostics.reportConnectionEvent(
3575                             BaseWifiDiagnostics.CONNECTION_EVENT_TIMEOUT);
3576                     break;
3577                 case 0:
3578                     // We want to notice any empty messages (with what == 0) that might crop up.
3579                     // For example, we may have recycled a message sent to multiple handlers.
3580                     Log.wtf(TAG, "Error! empty message encountered");
3581                     break;
3582                 default:
3583                     loge("Error! unhandled message" + message);
3584                     break;
3585             }
3586 
3587             if (handleStatus == HANDLED) {
3588                 logStateAndMessage(message, this);
3589             }
3590 
3591             return handleStatus;
3592         }
3593     }
3594 
3595     /**
3596      * Helper method to start other services and get state ready for client mode
3597      */
3598     private void setupClientMode() {
3599         Log.d(TAG, "setupClientMode() ifacename = " + mInterfaceName);
3600 
3601         setHighPerfModeEnabled(false);
3602 
3603         mWifiStateTracker.updateState(WifiStateTracker.INVALID);
3604         mIpClientCallbacks = new IpClientCallbacksImpl();
3605         mFacade.makeIpClient(mContext, mInterfaceName, mIpClientCallbacks);
3606         if (!mIpClientCallbacks.awaitCreation()) {
3607             Log.wtf(getName(), "Timeout waiting for IpClient");
3608         }
3609 
3610         setMulticastFilter(true);
3611         registerForWifiMonitorEvents();
3612         mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
3613         setSupplicantLogLevel();
3614 
3615         // reset state related to supplicant starting
3616         mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
3617         // Initialize data structures
3618         mLastBssid = null;
3619         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
3620         mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
3621         mLastSimBasedConnectionCarrierName = null;
3622         mLastSignalLevel = -1;
3623         if (isConnectedMacRandomizationEnabled()) {
3624             mWifiNative.setMacAddress(mInterfaceName, MacAddressUtils.createRandomUnicastAddress());
3625         }
3626         mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
3627         // TODO: b/79504296 This broadcast has been deprecated and should be removed
3628         sendSupplicantConnectionChangedBroadcast(true);
3629 
3630         mWifiNative.setExternalSim(mInterfaceName, true);
3631 
3632         mCountryCode.setReadyForChange(true);
3633 
3634         mWifiDiagnostics.startPktFateMonitoring(mInterfaceName);
3635         mWifiDiagnostics.startLogging(mInterfaceName);
3636 
3637         mMboOceController.enable();
3638         mWifiDataStall.enablePhoneStateListener();
3639 
3640         /**
3641          * Enable bluetooth coexistence scan mode when bluetooth connection is active.
3642          * When this mode is on, some of the low-level scan parameters used by the
3643          * driver are changed to reduce interference with bluetooth
3644          */
3645         mWifiNative.setBluetoothCoexistenceScanMode(mInterfaceName, mBluetoothConnectionActive);
3646         sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
3647 
3648         // Disable legacy multicast filtering, which on some chipsets defaults to enabled.
3649         // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
3650         // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
3651         // IpClient.Callback.setFallbackMulticastFilter()
3652         mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName);
3653         mWifiNative.stopFilteringMulticastV6Packets(mInterfaceName);
3654 
3655         // Set the right suspend mode settings
3656         mWifiNative.setSuspendOptimizations(mInterfaceName, mSuspendOptNeedsDisabled == 0
3657                 && mContext.getResources().getBoolean(
3658                         R.bool.config_wifiSuspendOptimizationsEnabled));
3659 
3660         setPowerSave(true);
3661 
3662         // Disable wpa_supplicant from auto reconnecting.
3663         mWifiNative.enableStaAutoReconnect(mInterfaceName, false);
3664         // STA has higher priority over P2P
3665         mWifiNative.setConcurrencyPriority(true);
3666     }
3667 
3668     /**
3669      * Helper method to stop external services and clean up state from client mode.
3670      */
3671     private void stopClientMode() {
3672         handleNetworkDisconnect();
3673         // exiting supplicant started state is now only applicable to client mode
3674         mWifiDiagnostics.stopLogging(mInterfaceName);
3675 
3676         mMboOceController.disable();
3677         mWifiDataStall.disablePhoneStateListener();
3678         if (mIpClient != null && mIpClient.shutdown()) {
3679             // Block to make sure IpClient has really shut down, lest cleanup
3680             // race with, say, bringup code over in tethering.
3681             mIpClientCallbacks.awaitShutdown();
3682         }
3683         mCountryCode.setReadyForChange(false);
3684         mInterfaceName = null;
3685         mWifiScoreReport.setInterfaceName(null);
3686         // TODO: b/79504296 This broadcast has been deprecated and should be removed
3687         sendSupplicantConnectionChangedBroadcast(false);
3688 
3689         // Let's remove any ephemeral or passpoint networks.
3690         mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks();
3691         mWifiConfigManager.clearUserTemporarilyDisabledList();
3692     }
3693 
3694     void registerConnected() {
3695         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
3696             mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId);
3697             // Notify PasspointManager of Passpoint network connected event.
3698             WifiConfiguration currentNetwork = getCurrentWifiConfiguration();
3699             if (currentNetwork != null && currentNetwork.isPasspoint()) {
3700                 mPasspointManager.onPasspointNetworkConnected(currentNetwork.getKey());
3701             }
3702         }
3703     }
3704 
3705     void registerDisconnected() {
3706         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
3707             mWifiConfigManager.updateNetworkAfterDisconnect(mLastNetworkId);
3708         }
3709     }
3710 
3711     /**
3712      * Returns WifiConfiguration object corresponding to the currently connected network, null if
3713      * not connected.
3714      */
3715     public WifiConfiguration getCurrentWifiConfiguration() {
3716         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
3717             return null;
3718         }
3719         return mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
3720     }
3721 
3722     private WifiConfiguration getTargetWifiConfiguration() {
3723         if (mTargetNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
3724             return null;
3725         }
3726         return mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
3727     }
3728 
3729     ScanResult getCurrentScanResult() {
3730         WifiConfiguration config = getCurrentWifiConfiguration();
3731         if (config == null) {
3732             return null;
3733         }
3734         String bssid = mWifiInfo.getBSSID();
3735         if (bssid == null) {
3736             bssid = mTargetBssid;
3737         }
3738         ScanDetailCache scanDetailCache =
3739                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
3740 
3741         if (scanDetailCache == null) {
3742             return null;
3743         }
3744 
3745         return scanDetailCache.getScanResult(bssid);
3746     }
3747 
3748     String getCurrentBSSID() {
3749         return mLastBssid;
3750     }
3751 
3752     MacAddress getCurrentBssid() {
3753         MacAddress bssid = null;
3754         try {
3755             bssid = (mLastBssid != null) ? MacAddress.fromString(mLastBssid) : null;
3756         } catch (IllegalArgumentException e) {
3757             Log.e(TAG, "Invalid BSSID format: " + mLastBssid);
3758         }
3759         return bssid;
3760     }
3761 
3762     void connectToNetwork(WifiConfiguration config) {
3763         if ((config != null) && mWifiNative.connectToNetwork(mInterfaceName, config)) {
3764             mWifiInjector.getWifiLastResortWatchdog().noteStartConnectTime();
3765             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
3766             mLastConnectAttemptTimestamp = mClock.getWallClockMillis();
3767             mIsAutoRoaming = false;
3768             if (getCurrentState() != mDisconnectedState) {
3769                 transitionTo(mDisconnectingState);
3770             }
3771         } else {
3772             loge("CMD_START_CONNECT Failed to start connection to network " + config);
3773             mTargetWifiConfiguration = null;
3774             stopIpClient();
3775             reportConnectionAttemptEnd(
3776                     WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
3777                     WifiMetricsProto.ConnectionEvent.HLF_NONE,
3778                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
3779         }
3780     }
3781 
3782     class ConnectModeState extends State {
3783 
3784         @Override
3785         public void enter() {
3786             Log.d(TAG, "entering ConnectModeState: ifaceName = " + mInterfaceName);
3787             mOperationalMode = CONNECT_MODE;
3788             setupClientMode();
3789             if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
3790                 loge("Failed to remove networks on entering connect mode");
3791             }
3792             mWifiInfo.reset();
3793             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
3794 
3795             mWifiInjector.getWakeupController().reset();
3796             sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
3797 
3798             // Inform WifiConnectivityManager that Wifi is enabled
3799             mWifiConnectivityManager.setWifiEnabled(true);
3800             mNetworkFactory.setWifiState(true);
3801             // Inform metrics that Wifi is Enabled (but not yet connected)
3802             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
3803             mWifiMetrics.logStaEvent(StaEvent.TYPE_WIFI_ENABLED);
3804             mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
3805             mWifiHealthMonitor.setWifiEnabled(true);
3806             mWifiDataStall.init();
3807         }
3808 
3809         @Override
3810         public void exit() {
3811             mOperationalMode = DISABLED_MODE;
3812 
3813             // Inform WifiConnectivityManager that Wifi is disabled
3814             mWifiConnectivityManager.setWifiEnabled(false);
3815             mNetworkFactory.setWifiState(false);
3816             // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
3817             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
3818             mWifiMetrics.logStaEvent(StaEvent.TYPE_WIFI_DISABLED);
3819             // Inform scorecard that wifi is being disabled
3820             mWifiScoreCard.noteWifiDisabled(mWifiInfo);
3821 
3822             if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
3823                 loge("Failed to remove networks on exiting connect mode");
3824             }
3825             mWifiInfo.reset();
3826             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
3827             mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
3828             mWifiHealthMonitor.setWifiEnabled(false);
3829             mWifiDataStall.reset();
3830             stopClientMode();
3831         }
3832 
3833         @Override
3834         public boolean processMessage(Message message) {
3835             WifiConfiguration config;
3836             int netId;
3837             boolean ok;
3838             boolean didDisconnect;
3839             String bssid;
3840             String ssid;
3841             NetworkUpdateResult result;
3842             Set<Integer> removedNetworkIds;
3843             int reasonCode;
3844             boolean timedOut;
3845             boolean handleStatus = HANDLED;
3846             int callbackIdentifier = -1;
3847 
3848             int level2FailureReason =
3849                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN;
3850             switch (message.what) {
3851                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3852                     stopIpClient();
3853                     mWifiDiagnostics.captureBugReportData(
3854                             WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
3855                     mDidBlackListBSSID = false;
3856                     bssid = (String) message.obj;
3857                     timedOut = message.arg1 > 0;
3858                     reasonCode = message.arg2;
3859                     Log.d(TAG, "Association Rejection event: bssid=" + bssid + " reason code="
3860                             + reasonCode + " timedOut=" + Boolean.toString(timedOut));
3861                     if (bssid == null || TextUtils.isEmpty(bssid)) {
3862                         // If BSSID is null, use the target roam BSSID
3863                         bssid = mTargetBssid;
3864                     } else if (mTargetBssid == SUPPLICANT_BSSID_ANY) {
3865                         // This is needed by BssidBlocklistMonitor to block continuously
3866                         // failing BSSIDs. Need to set here because mTargetBssid is currently
3867                         // not being set until association success.
3868                         mTargetBssid = bssid;
3869                     }
3870                     mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
3871                             WifiConfiguration.NetworkSelectionStatus
3872                             .DISABLED_ASSOCIATION_REJECTION);
3873                     mWifiConfigManager.setRecentFailureAssociationStatus(mTargetNetworkId,
3874                             reasonCode);
3875 
3876                     if (reasonCode == REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA) {
3877                         level2FailureReason = WifiMetricsProto.ConnectionEvent
3878                                 .ASSOCIATION_REJECTION_AP_UNABLE_TO_HANDLE_NEW_STA;
3879                     }
3880                     // If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
3881                     reportConnectionAttemptEnd(
3882                             timedOut
3883                                     ? WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT
3884                                     : WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
3885                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
3886                             level2FailureReason);
3887                     if (reasonCode != REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA) {
3888                         mWifiInjector.getWifiLastResortWatchdog()
3889                                 .noteConnectionFailureAndTriggerIfNeeded(
3890                                         getTargetSsid(), bssid,
3891                                         WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
3892                     }
3893                     mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
3894                     break;
3895                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3896                     stopIpClient();
3897                     mWifiDiagnostics.captureBugReportData(
3898                             WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
3899                     int disableReason = WifiConfiguration.NetworkSelectionStatus
3900                             .DISABLED_AUTHENTICATION_FAILURE;
3901                     reasonCode = message.arg1;
3902                     WifiConfiguration targetedNetwork =
3903                             mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
3904                     // Check if this is a permanent wrong password failure.
3905                     if (isPermanentWrongPasswordFailure(mTargetNetworkId, reasonCode)) {
3906                         disableReason = WifiConfiguration.NetworkSelectionStatus
3907                                 .DISABLED_BY_WRONG_PASSWORD;
3908                         if (targetedNetwork != null) {
3909                             mWrongPasswordNotifier.onWrongPasswordError(
3910                                     targetedNetwork.SSID);
3911                         }
3912                     } else if (reasonCode == WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
3913                         int errorCode = message.arg2;
3914                         if (targetedNetwork != null && targetedNetwork.enterpriseConfig != null
3915                                 && targetedNetwork.enterpriseConfig.isAuthenticationSimBased()) {
3916                             mEapFailureNotifier.onEapFailure(errorCode, targetedNetwork);
3917                         }
3918                         handleEapAuthFailure(mTargetNetworkId, errorCode);
3919                         if (errorCode == WifiNative.EAP_SIM_NOT_SUBSCRIBED) {
3920                             disableReason = WifiConfiguration.NetworkSelectionStatus
3921                                 .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION;
3922                         }
3923                     }
3924                     mWifiConfigManager.updateNetworkSelectionStatus(
3925                             mTargetNetworkId, disableReason);
3926                     mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);
3927 
3928                     //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
3929                     switch (reasonCode) {
3930                         case WifiManager.ERROR_AUTH_FAILURE_NONE:
3931                             level2FailureReason =
3932                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE;
3933                             break;
3934                         case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
3935                             level2FailureReason =
3936                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_TIMEOUT;
3937                             break;
3938                         case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
3939                             level2FailureReason =
3940                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD;
3941                             break;
3942                         case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
3943                             level2FailureReason =
3944                                     WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE;
3945                             break;
3946                         default:
3947                             level2FailureReason =
3948                                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN;
3949                             break;
3950                     }
3951                     reportConnectionAttemptEnd(
3952                             WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
3953                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
3954                             level2FailureReason);
3955                     if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD && reasonCode
3956                             != WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE) {
3957                         mWifiInjector.getWifiLastResortWatchdog()
3958                                 .noteConnectionFailureAndTriggerIfNeeded(
3959                                         getTargetSsid(),
3960                                         (mLastBssid == null) ? mTargetBssid : mLastBssid,
3961                                         WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
3962                     }
3963                     break;
3964                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3965                     SupplicantState state = handleSupplicantStateChange(message);
3966 
3967                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
3968                     // when authentication times out after a successful connection,
3969                     // we can figure this from the supplicant state. If supplicant
3970                     // state is DISCONNECTED, but the agent is not disconnected, we
3971                     // need to handle a disconnection
3972                     if (state == SupplicantState.DISCONNECTED && mNetworkAgent != null) {
3973                         if (mVerboseLoggingEnabled) {
3974                             log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
3975                         }
3976                         handleNetworkDisconnect();
3977                         transitionTo(mDisconnectedState);
3978                     }
3979 
3980                     if (state == SupplicantState.COMPLETED) {
3981                         mWifiScoreReport.noteIpCheck();
3982                     }
3983                     break;
3984                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
3985                     if (message.arg1 == 1) {
3986                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
3987                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
3988                         mWifiNative.disconnect(mInterfaceName);
3989                         mTemporarilyDisconnectWifi = true;
3990                     } else {
3991                         mWifiNative.reconnect(mInterfaceName);
3992                         mTemporarilyDisconnectWifi = false;
3993                     }
3994                     break;
3995                 case WifiMonitor.SUP_REQUEST_IDENTITY:
3996                     netId = message.arg2;
3997                     boolean identitySent = false;
3998                     // For SIM & AKA/AKA' EAP method Only, get identity from ICC
3999                     if (mTargetWifiConfiguration != null
4000                             && mTargetWifiConfiguration.networkId == netId
4001                             && mTargetWifiConfiguration.enterpriseConfig != null
4002                             && mTargetWifiConfiguration.enterpriseConfig
4003                                     .isAuthenticationSimBased()) {
4004                         // Pair<identity, encrypted identity>
4005                         Pair<String, String> identityPair = mWifiCarrierInfoManager
4006                                 .getSimIdentity(mTargetWifiConfiguration);
4007                         if (identityPair != null && identityPair.first != null) {
4008                             Log.i(TAG, "SUP_REQUEST_IDENTITY: identityPair=["
4009                                     + ((identityPair.first.length() >= 7)
4010                                     ? identityPair.first.substring(0, 7 /* Prefix+PLMN ID */)
4011                                     + "****"
4012                                     : identityPair.first) + ", "
4013                                     + (!TextUtils.isEmpty(identityPair.second) ? identityPair.second
4014                                     : "<NONE>") + "]");
4015                             mWifiNative.simIdentityResponse(mInterfaceName, identityPair.first,
4016                                     identityPair.second);
4017                             identitySent = true;
4018                         } else {
4019                             Log.e(TAG, "Unable to retrieve identity from Telephony");
4020                         }
4021                     }
4022 
4023                     if (!identitySent) {
4024                         // Supplicant lacks credentials to connect to that network, hence black list
4025                         ssid = (String) message.obj;
4026                         if (mTargetWifiConfiguration != null && ssid != null
4027                                 && mTargetWifiConfiguration.SSID != null
4028                                 && mTargetWifiConfiguration.SSID.equals("\"" + ssid + "\"")) {
4029                             mWifiConfigManager.updateNetworkSelectionStatus(
4030                                     mTargetWifiConfiguration.networkId,
4031                                     WifiConfiguration.NetworkSelectionStatus
4032                                             .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
4033                         }
4034                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
4035                                 StaEvent.DISCONNECT_GENERIC);
4036                         mWifiNative.disconnect(mInterfaceName);
4037                     }
4038                     break;
4039                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
4040                     logd("Received SUP_REQUEST_SIM_AUTH");
4041                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
4042                     if (requestData != null) {
4043                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
4044                             handleGsmAuthRequest(requestData);
4045                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
4046                                 || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
4047                             handle3GAuthRequest(requestData);
4048                         }
4049                     } else {
4050                         loge("Invalid SIM auth request");
4051                     }
4052                     break;
4053                 case CMD_START_SUBSCRIPTION_PROVISIONING:
4054                     IProvisioningCallback callback = (IProvisioningCallback) message.obj;
4055                     OsuProvider provider =
4056                             (OsuProvider) message.getData().getParcelable(EXTRA_OSU_PROVIDER);
4057                     int res = mPasspointManager.startSubscriptionProvisioning(
4058                                     message.arg1, provider, callback) ? 1 : 0;
4059                     replyToMessage(message, message.what, res);
4060                     break;
4061                 case CMD_RECONNECT:
4062                     WorkSource workSource = (WorkSource) message.obj;
4063                     mWifiConnectivityManager.forceConnectivityScan(workSource);
4064                     break;
4065                 case CMD_REASSOCIATE:
4066                     mLastConnectAttemptTimestamp = mClock.getWallClockMillis();
4067                     mWifiNative.reassociate(mInterfaceName);
4068                     break;
4069                 case CMD_START_ROAM:
4070                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
4071                     break;
4072                 case CMD_START_CONNECT:
4073                     /* connect command coming from auto-join */
4074                     netId = message.arg1;
4075                     int uid = message.arg2;
4076                     bssid = (String) message.obj;
4077                     mSentHLPs = false;
4078 
4079                     if (!hasConnectionRequests()) {
4080                         if (mNetworkAgent == null) {
4081                             loge("CMD_START_CONNECT but no requests and not connected,"
4082                                     + " bailing");
4083                             break;
4084                         } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4085                             loge("CMD_START_CONNECT but no requests and connected, but app "
4086                                     + "does not have sufficient permissions, bailing");
4087                             break;
4088                         }
4089                     }
4090                     config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
4091                     logd("CMD_START_CONNECT "
4092                             + " my state " + getCurrentState().getName()
4093                             + " nid=" + Integer.toString(netId)
4094                             + " roam=" + Boolean.toString(mIsAutoRoaming));
4095                     if (config == null) {
4096                         loge("CMD_START_CONNECT and no config, bail out...");
4097                         break;
4098                     }
4099                     mTargetNetworkId = netId;
4100                     // Update scorecard while there is still state from existing connection
4101                     int scanRssi = mWifiConfigManager.findScanRssi(netId,
4102                             mWifiHealthMonitor.getScanRssiValidTimeMs());
4103                     mWifiScoreCard.noteConnectionAttempt(mWifiInfo, scanRssi, config.SSID);
4104                     mBssidBlocklistMonitor.updateFirmwareRoamingConfiguration(config.SSID);
4105 
4106                     updateWifiConfigOnStartConnection(config, bssid);
4107                     reportConnectionAttemptStart(config, mTargetBssid,
4108                             WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
4109 
4110                     String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);
4111                     mWifiInfo.setMacAddress(currentMacAddress);
4112                     Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address");
4113 
4114                     mTargetWifiConfiguration = config;
4115                     /* Check for FILS configuration again after updating the config */
4116                     if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256)
4117                             || config.allowedKeyManagement.get(
4118                             WifiConfiguration.KeyMgmt.FILS_SHA384)) {
4119 
4120                         boolean isIpClientStarted = startIpClient(config, true);
4121                         if (isIpClientStarted) {
4122                             mIpClientWithPreConnection = true;
4123                             break;
4124                         }
4125                     }
4126                     connectToNetwork(config);
4127                     break;
4128                 case CMD_START_FILS_CONNECTION:
4129                     mWifiMetrics.incrementConnectRequestWithFilsAkmCount();
4130                     List<Layer2PacketParcelable> packets;
4131                     packets = (List<Layer2PacketParcelable>) message.obj;
4132                     if (mVerboseLoggingEnabled) {
4133                         Log.d(TAG, "Send HLP IEs to supplicant");
4134                     }
4135                     addLayer2PacketsToHlpReq(packets);
4136                     config = mTargetWifiConfiguration;
4137                     connectToNetwork(config);
4138                     break;
4139                 case CMD_CONNECT_NETWORK:
4140                     callbackIdentifier = message.arg2;
4141                     result = (NetworkUpdateResult) message.obj;
4142                     netId = result.getNetworkId();
4143                     connectToUserSelectNetwork(
4144                             netId, message.sendingUid, result.hasCredentialChanged());
4145                     mWifiMetrics.logStaEvent(
4146                             StaEvent.TYPE_CONNECT_NETWORK,
4147                             mWifiConfigManager.getConfiguredNetwork(netId));
4148                     sendActionListenerSuccess(callbackIdentifier);
4149                     break;
4150                 case CMD_SAVE_NETWORK:
4151                     callbackIdentifier = message.arg2;
4152                     result = (NetworkUpdateResult) message.obj;
4153                     netId = result.getNetworkId();
4154                     if (mWifiInfo.getNetworkId() == netId) {
4155                         if (result.hasCredentialChanged()) {
4156                             // The network credentials changed and we're connected to this network,
4157                             // start a new connection with the updated credentials.
4158                             logi("CMD_SAVE_NETWORK credential changed for nid="
4159                                     + netId + ". Reconnecting.");
4160                             startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
4161                         } else {
4162                             if (result.hasProxyChanged()) {
4163                                 if (mIpClient != null) {
4164                                     log("Reconfiguring proxy on connection");
4165                                     WifiConfiguration currentConfig = getCurrentWifiConfiguration();
4166                                     if (currentConfig != null) {
4167                                         mIpClient.setHttpProxy(currentConfig.getHttpProxy());
4168                                     } else {
4169                                         Log.w(TAG,
4170                                                 "CMD_SAVE_NETWORK proxy change - but no current "
4171                                                         + "Wi-Fi config");
4172                                     }
4173                                 }
4174                             }
4175                             if (result.hasIpChanged()) {
4176                                 // The current connection configuration was changed
4177                                 // We switched from DHCP to static or from static to DHCP, or the
4178                                 // static IP address has changed.
4179                                 log("Reconfiguring IP on connection");
4180                                 WifiConfiguration currentConfig = getCurrentWifiConfiguration();
4181                                 if (currentConfig != null) {
4182                                     transitionTo(mObtainingIpState);
4183                                 } else {
4184                                     Log.w(TAG, "CMD_SAVE_NETWORK Ip change - but no current "
4185                                             + "Wi-Fi config");
4186                                 }
4187                             }
4188                         }
4189                     } else if (mWifiInfo.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID
4190                             && result.hasCredentialChanged()) {
4191                         logi("CMD_SAVE_NETWORK credential changed for nid="
4192                                 + netId + " while disconnected. Connecting.");
4193                         startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
4194                     }
4195                     sendActionListenerSuccess(callbackIdentifier);
4196                     break;
4197                 case WifiMonitor.ASSOCIATED_BSSID_EVENT:
4198                     // This is where we can confirm the connection BSSID. Use it to find the
4199                     // right ScanDetail to populate metrics.
4200                     String someBssid = (String) message.obj;
4201                     if (someBssid != null) {
4202                         // Get the ScanDetail associated with this BSSID.
4203                         ScanDetailCache scanDetailCache =
4204                                 mWifiConfigManager.getScanDetailCacheForNetwork(mTargetNetworkId);
4205                         if (scanDetailCache != null) {
4206                             mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
4207                                     someBssid));
4208                         }
4209                         // Update last associated BSSID
4210                         mLastBssid = someBssid;
4211                     }
4212                     handleStatus = NOT_HANDLED;
4213                     break;
4214                 case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
4215                     mWifiMetrics.incrementL2ConnectionThroughFilsAuthCount();
4216                     mSentHLPs = true;
4217                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
4218                     if (mVerboseLoggingEnabled) log("Network connection established");
4219                     mLastNetworkId = message.arg1;
4220                     mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
4221                     mLastBssid = (String) message.obj;
4222                     reasonCode = message.arg2;
4223                     // TODO: This check should not be needed after ClientModeImpl refactor.
4224                     // Currently, the last connected network configuration is left in
4225                     // wpa_supplicant, this may result in wpa_supplicant initiating connection
4226                     // to it after a config store reload. Hence the old network Id lookups may not
4227                     // work, so disconnect the network and let network selector reselect a new
4228                     // network.
4229                     config = getCurrentWifiConfiguration();
4230                     if (config != null) {
4231                         mWifiInfo.setBSSID(mLastBssid);
4232                         mWifiInfo.setNetworkId(mLastNetworkId);
4233                         mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
4234 
4235                         ScanDetailCache scanDetailCache =
4236                                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
4237                         if (scanDetailCache != null && mLastBssid != null) {
4238                             ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
4239                             if (scanResult != null) {
4240                                 mWifiInfo.setFrequency(scanResult.frequency);
4241                             }
4242                         }
4243 
4244                         // We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA'
4245                         if (config.enterpriseConfig != null
4246                                 && config.enterpriseConfig.isAuthenticationSimBased()) {
4247                             mLastSubId = mWifiCarrierInfoManager.getBestMatchSubscriptionId(config);
4248                             mLastSimBasedConnectionCarrierName =
4249                                 mWifiCarrierInfoManager.getCarrierNameforSubId(mLastSubId);
4250                             String anonymousIdentity =
4251                                     mWifiNative.getEapAnonymousIdentity(mInterfaceName);
4252                             if (!TextUtils.isEmpty(anonymousIdentity)
4253                                     && !WifiCarrierInfoManager
4254                                     .isAnonymousAtRealmIdentity(anonymousIdentity)) {
4255                                 String decoratedPseudonym = mWifiCarrierInfoManager
4256                                         .decoratePseudonymWith3GppRealm(config,
4257                                                 anonymousIdentity);
4258                                 if (decoratedPseudonym != null) {
4259                                     anonymousIdentity = decoratedPseudonym;
4260                                 }
4261                                 if (mVerboseLoggingEnabled) {
4262                                     log("EAP Pseudonym: " + anonymousIdentity);
4263                                 }
4264                                 // Save the pseudonym only if it is a real one
4265                                 config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
4266                             } else {
4267                                 // Clear any stored pseudonyms
4268                                 config.enterpriseConfig.setAnonymousIdentity(null);
4269                             }
4270                             mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
4271                         }
4272                         transitionTo(mObtainingIpState);
4273                     } else {
4274                         logw("Connected to unknown networkId " + mLastNetworkId
4275                                 + ", disconnecting...");
4276                         sendMessage(CMD_DISCONNECT);
4277                     }
4278                     break;
4279                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4280                     // Calling handleNetworkDisconnect here is redundant because we might already
4281                     // have called it when leaving L2ConnectedState to go to disconnecting state
4282                     // or thru other path
4283                     // We should normally check the mWifiInfo or mLastNetworkId so as to check
4284                     // if they are valid, and only in this case call handleNEtworkDisconnect,
4285                     // TODO: this should be fixed for a L MR release
4286                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of
4287                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
4288                     // at the chip etc...
4289                     if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
4290                     clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
4291                     handleNetworkDisconnect();
4292                     transitionTo(mDisconnectedState);
4293                     break;
4294                 case CMD_QUERY_OSU_ICON:
4295                     mPasspointManager.queryPasspointIcon(
4296                             ((Bundle) message.obj).getLong(EXTRA_OSU_ICON_QUERY_BSSID),
4297                             ((Bundle) message.obj).getString(EXTRA_OSU_ICON_QUERY_FILENAME));
4298                     break;
4299                 case WifiMonitor.TARGET_BSSID_EVENT:
4300                     // Trying to associate to this BSSID
4301                     if (message.obj != null) {
4302                         mTargetBssid = (String) message.obj;
4303                     }
4304                     break;
4305                 case CMD_GET_LINK_LAYER_STATS:
4306                     WifiLinkLayerStats stats = getWifiLinkLayerStats();
4307                     replyToMessage(message, message.what, stats);
4308                     break;
4309                 case CMD_RESET_SIM_NETWORKS:
4310                     log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
4311                     int resetReason = message.arg1;
4312                     if (resetReason == RESET_SIM_REASON_SIM_INSERTED) {
4313                         // whenever a SIM is inserted clear all SIM related notifications
4314                         mSimRequiredNotifier.dismissSimRequiredNotification();
4315                     } else {
4316                         mWifiConfigManager.resetSimNetworks();
4317                     }
4318                     if (resetReason != RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED) {
4319                         mWifiNetworkSuggestionsManager.resetCarrierPrivilegedApps();
4320                     }
4321                     break;
4322                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
4323                     // If BT was connected and then turned off, there is no CONNECTION_STATE_CHANGE
4324                     // message. So we need to rely on STATE_CHANGE message to detect on->off
4325                     // transition and update mBluetoothConnectionActive status correctly.
4326                     mBluetoothConnectionActive = mBluetoothConnectionActive
4327                             && message.arg1 != BluetoothAdapter.STATE_OFF;
4328                     mWifiNative.setBluetoothCoexistenceScanMode(
4329                             mInterfaceName, mBluetoothConnectionActive);
4330                     mWifiConnectivityManager.setBluetoothConnected(mBluetoothConnectionActive);
4331                     break;
4332                 case CMD_BLUETOOTH_ADAPTER_CONNECTION_STATE_CHANGE:
4333                     // Transition to a non-disconnected state does correctly
4334                     // indicate BT is connected or being connected.
4335                     mBluetoothConnectionActive =
4336                             message.arg1 != BluetoothAdapter.STATE_DISCONNECTED;
4337                     mWifiNative.setBluetoothCoexistenceScanMode(
4338                             mInterfaceName, mBluetoothConnectionActive);
4339                     mWifiConnectivityManager.setBluetoothConnected(mBluetoothConnectionActive);
4340                     break;
4341                 case CMD_SET_SUSPEND_OPT_ENABLED:
4342                     if (message.arg1 == 1) {
4343                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
4344                         if (message.arg2 == 1) {
4345                             mSuspendWakeLock.release();
4346                         }
4347                     } else {
4348                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
4349                     }
4350                     break;
4351                 case CMD_SET_HIGH_PERF_MODE:
4352                     if (message.arg1 == 1) {
4353                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
4354                     } else {
4355                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
4356                     }
4357                     break;
4358                 case CMD_ENABLE_TDLS:
4359                     if (message.obj != null) {
4360                         String remoteAddress = (String) message.obj;
4361                         boolean enable = (message.arg1 == 1);
4362                         mWifiNative.startTdls(mInterfaceName, remoteAddress, enable);
4363                     }
4364                     break;
4365                 case WifiMonitor.ANQP_DONE_EVENT:
4366                     // TODO(zqiu): remove this when switch over to wificond for ANQP requests.
4367                     mPasspointManager.notifyANQPDone((AnqpEvent) message.obj);
4368                     break;
4369                 case CMD_STOP_IP_PACKET_OFFLOAD: {
4370                     int slot = message.arg1;
4371                     int ret = stopWifiIPPacketOffload(slot);
4372                     if (mNetworkAgent != null) {
4373                         mNetworkAgent.sendSocketKeepaliveEvent(slot, ret);
4374                     }
4375                     break;
4376                 }
4377                 case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4378                     // TODO(zqiu): remove this when switch over to wificond for icon requests.
4379                     mPasspointManager.notifyIconDone((IconEvent) message.obj);
4380                     break;
4381                 case WifiMonitor.HS20_REMEDIATION_EVENT:
4382                     // TODO(zqiu): remove this when switch over to wificond for WNM frames
4383                     // monitoring.
4384                     mPasspointManager.receivedWnmFrame((WnmData) message.obj);
4385                     break;
4386                 case WifiMonitor.MBO_OCE_BSS_TM_HANDLING_DONE:
4387                     handleBssTransitionRequest((BtmFrameData) message.obj);
4388                     break;
4389                 case CMD_CONFIG_ND_OFFLOAD:
4390                     final boolean enabled = (message.arg1 > 0);
4391                     mWifiNative.configureNeighborDiscoveryOffload(mInterfaceName, enabled);
4392                     break;
4393                 case CMD_PRE_DHCP_ACTION:
4394                 case CMD_PRE_DHCP_ACTION_COMPLETE:
4395                 case CMD_POST_DHCP_ACTION:
4396                 case CMD_IPV4_PROVISIONING_SUCCESS:
4397                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
4398                 case CMD_IPV4_PROVISIONING_FAILURE:
4399                     handleStatus = handleL3MessagesWhenNotConnected(message);
4400                     break;
4401                 default:
4402                     handleStatus = NOT_HANDLED;
4403                     break;
4404             }
4405 
4406             if (handleStatus == HANDLED) {
4407                 logStateAndMessage(message, this);
4408             }
4409 
4410             return handleStatus;
4411         }
4412     }
4413 
handleL3MessagesWhenNotConnected(Message message)4414     private boolean handleL3MessagesWhenNotConnected(Message message) {
4415         boolean handleStatus = HANDLED;
4416 
4417         if (!mIpClientWithPreConnection) {
4418             return NOT_HANDLED;
4419         }
4420 
4421         switch (message.what) {
4422             case CMD_PRE_DHCP_ACTION:
4423                 handlePreDhcpSetup();
4424                 break;
4425             case CMD_PRE_DHCP_ACTION_COMPLETE:
4426                 if (mIpClient != null) {
4427                     mIpClient.completedPreDhcpAction();
4428                 }
4429                 break;
4430             case CMD_IPV4_PROVISIONING_FAILURE:
4431                 stopDhcpSetup();
4432                 deferMessage(message);
4433                 break;
4434             case CMD_POST_DHCP_ACTION:
4435             case CMD_IPV4_PROVISIONING_SUCCESS:
4436             case CMD_IP_CONFIGURATION_SUCCESSFUL:
4437                 deferMessage(message);
4438                 break;
4439             default:
4440                 return NOT_HANDLED;
4441         }
4442 
4443         return handleStatus;
4444     }
4445 
createNetworkAgentSpecifier( @onNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid)4446     private WifiNetworkAgentSpecifier createNetworkAgentSpecifier(
4447             @NonNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid) {
4448         currentWifiConfiguration.BSSID = currentBssid;
4449         WifiNetworkAgentSpecifier wns =
4450                 new WifiNetworkAgentSpecifier(currentWifiConfiguration);
4451         return wns;
4452     }
4453 
getCapabilities(WifiConfiguration currentWifiConfiguration)4454     private NetworkCapabilities getCapabilities(WifiConfiguration currentWifiConfiguration) {
4455         final NetworkCapabilities.Builder builder =
4456                 new NetworkCapabilities.Builder(mNetworkCapabilitiesFilter);
4457         // MatchAllNetworkSpecifier set in the mNetworkCapabilitiesFilter should never be set in the
4458         // agent's specifier.
4459         builder.setNetworkSpecifier(null);
4460         if (currentWifiConfiguration == null) {
4461             return builder.build();
4462         }
4463 
4464         if (mWifiInfo.isTrusted()) {
4465             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
4466         } else {
4467             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
4468         }
4469 
4470         builder.setOwnerUid(currentWifiConfiguration.creatorUid);
4471         builder.setAdministratorUids(new int[] {currentWifiConfiguration.creatorUid});
4472 
4473         if (!WifiConfiguration.isMetered(currentWifiConfiguration, mWifiInfo)) {
4474             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
4475         } else {
4476             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
4477         }
4478 
4479         if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI) {
4480             builder.setSignalStrength(mWifiInfo.getRssi());
4481         } else {
4482             builder.setSignalStrength(NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
4483         }
4484 
4485         if (currentWifiConfiguration.osu) {
4486             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
4487         }
4488 
4489         if (!mWifiInfo.getSSID().equals(WifiManager.UNKNOWN_SSID)) {
4490             builder.setSsid(mWifiInfo.getSSID());
4491         }
4492         Pair<Integer, String> specificRequestUidAndPackageName =
4493                 mNetworkFactory.getSpecificNetworkRequestUidAndPackageName(
4494                         currentWifiConfiguration);
4495         // There is an active specific request.
4496         if (specificRequestUidAndPackageName.first != Process.INVALID_UID) {
4497             // Remove internet capability.
4498             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
4499             // Fill up the uid/packageName for this connection.
4500             builder.setRequestorUid(specificRequestUidAndPackageName.first);
4501             builder.setRequestorPackageName(specificRequestUidAndPackageName.second);
4502             // Fill up the network agent specifier for this connection.
4503             builder.setNetworkSpecifier(createNetworkAgentSpecifier(
4504                     currentWifiConfiguration, getCurrentBSSID()));
4505         }
4506         updateLinkBandwidth(builder);
4507         return builder.build();
4508     }
4509 
updateLinkBandwidth(NetworkCapabilities.Builder networkCapabilitiesBuilder)4510     private void updateLinkBandwidth(NetworkCapabilities.Builder networkCapabilitiesBuilder) {
4511         int rssiDbm = mWifiInfo.getRssi();
4512         int txTputKbps = INVALID_THROUGHPUT;
4513         int rxTputKbps = INVALID_THROUGHPUT;
4514         // If RSSI is available, check if throughput is available
4515         if (rssiDbm != WifiInfo.INVALID_RSSI && mWifiDataStall != null) {
4516             txTputKbps = mWifiDataStall.getTxThroughputKbps();
4517             rxTputKbps = mWifiDataStall.getRxThroughputKbps();
4518         }
4519         if (txTputKbps == INVALID_THROUGHPUT && rxTputKbps != INVALID_THROUGHPUT) {
4520             txTputKbps = rxTputKbps;
4521         } else if (rxTputKbps == INVALID_THROUGHPUT && txTputKbps != INVALID_THROUGHPUT) {
4522             rxTputKbps = txTputKbps;
4523         } else if (txTputKbps == INVALID_THROUGHPUT && rxTputKbps == INVALID_THROUGHPUT) {
4524             int maxTxLinkSpeedMbps = mWifiInfo.getMaxSupportedTxLinkSpeedMbps();
4525             int maxRxLinkSpeedMbps = mWifiInfo.getMaxSupportedRxLinkSpeedMbps();
4526             if (maxTxLinkSpeedMbps > 0) {
4527                 txTputKbps = maxTxLinkSpeedMbps * 1000;
4528             }
4529             if (maxRxLinkSpeedMbps > 0) {
4530                 rxTputKbps = maxRxLinkSpeedMbps * 1000;
4531             }
4532         }
4533         if (mVerboseLoggingEnabled) {
4534             logd("tx tput in kbps: " + txTputKbps);
4535             logd("rx tput in kbps: " + rxTputKbps);
4536         }
4537         if (txTputKbps > 0) {
4538             networkCapabilitiesBuilder.setLinkUpstreamBandwidthKbps(txTputKbps);
4539         }
4540         if (rxTputKbps > 0) {
4541             networkCapabilitiesBuilder.setLinkDownstreamBandwidthKbps(rxTputKbps);
4542         }
4543     }
4544 
4545     /**
4546      * Method to update network capabilities from the current WifiConfiguration.
4547      */
updateCapabilities()4548     public void updateCapabilities() {
4549         updateCapabilities(getCurrentWifiConfiguration());
4550     }
4551 
updateCapabilities(WifiConfiguration currentWifiConfiguration)4552     private void updateCapabilities(WifiConfiguration currentWifiConfiguration) {
4553         updateCapabilities(getCapabilities(currentWifiConfiguration));
4554     }
4555 
updateCapabilities(NetworkCapabilities networkCapabilities)4556     private void updateCapabilities(NetworkCapabilities networkCapabilities) {
4557         if (mNetworkAgent == null) {
4558             return;
4559         }
4560         mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
4561     }
4562 
handleEapAuthFailure(int networkId, int errorCode)4563     private void handleEapAuthFailure(int networkId, int errorCode) {
4564         WifiConfiguration targetedNetwork =
4565                 mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
4566         if (targetedNetwork != null) {
4567             switch (targetedNetwork.enterpriseConfig.getEapMethod()) {
4568                 case WifiEnterpriseConfig.Eap.SIM:
4569                 case WifiEnterpriseConfig.Eap.AKA:
4570                 case WifiEnterpriseConfig.Eap.AKA_PRIME:
4571                     if (errorCode == WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED) {
4572                         mWifiCarrierInfoManager.resetCarrierKeysForImsiEncryption(targetedNetwork);
4573                     }
4574                     break;
4575 
4576                 default:
4577                     // Do Nothing
4578             }
4579         }
4580     }
4581 
4582     private class WifiNetworkAgent extends NetworkAgent {
WifiNetworkAgent(Context c, Looper l, String tag, NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config, NetworkProvider provider)4583         WifiNetworkAgent(Context c, Looper l, String tag, NetworkCapabilities nc, LinkProperties lp,
4584                 int score, NetworkAgentConfig config, NetworkProvider provider) {
4585             super(c, l, tag, nc, lp, score, config, provider);
4586             register();
4587         }
4588         private int mLastNetworkStatus = -1; // To detect when the status really changes
4589 
4590         @Override
onNetworkUnwanted()4591         public void onNetworkUnwanted() {
4592             // Ignore if we're not the current networkAgent.
4593             if (this != mNetworkAgent) return;
4594             if (mVerboseLoggingEnabled) {
4595                 logd("WifiNetworkAgent -> Wifi unwanted score " + Integer.toString(
4596                         mWifiInfo.getScore()));
4597             }
4598             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
4599         }
4600 
4601         @Override
onValidationStatus(int status, @Nullable Uri redirectUri)4602         public void onValidationStatus(int status, @Nullable Uri redirectUri) {
4603             if (this != mNetworkAgent) return;
4604             if (status == mLastNetworkStatus) return;
4605             mLastNetworkStatus = status;
4606             if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID) {
4607                 if (mVerboseLoggingEnabled) {
4608                     logd("WifiNetworkAgent -> Wifi networkStatus invalid, score="
4609                             + Integer.toString(mWifiInfo.getScore()));
4610                 }
4611                 unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
4612             } else if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
4613                 if (mVerboseLoggingEnabled) {
4614                     logd("WifiNetworkAgent -> Wifi networkStatus valid, score= "
4615                             + Integer.toString(mWifiInfo.getScore()));
4616                 }
4617                 mWifiMetrics.logStaEvent(StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
4618                 doNetworkStatus(status);
4619             }
4620         }
4621 
4622         @Override
onSaveAcceptUnvalidated(boolean accept)4623         public void onSaveAcceptUnvalidated(boolean accept) {
4624             if (this != mNetworkAgent) return;
4625             ClientModeImpl.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
4626         }
4627 
4628         @Override
onStartSocketKeepalive(int slot, @NonNull Duration interval, @NonNull KeepalivePacketData packet)4629         public void onStartSocketKeepalive(int slot, @NonNull Duration interval,
4630                 @NonNull KeepalivePacketData packet) {
4631             if (this != mNetworkAgent) return;
4632             ClientModeImpl.this.sendMessage(
4633                     CMD_START_IP_PACKET_OFFLOAD, slot, (int) interval.getSeconds(), packet);
4634         }
4635 
4636         @Override
onStopSocketKeepalive(int slot)4637         public void onStopSocketKeepalive(int slot) {
4638             if (this != mNetworkAgent) return;
4639             ClientModeImpl.this.sendMessage(CMD_STOP_IP_PACKET_OFFLOAD, slot);
4640         }
4641 
4642         @Override
onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet)4643         public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) {
4644             if (this != mNetworkAgent) return;
4645             ClientModeImpl.this.sendMessage(
4646                     CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0, packet);
4647         }
4648 
4649         @Override
onRemoveKeepalivePacketFilter(int slot)4650         public void onRemoveKeepalivePacketFilter(int slot) {
4651             if (this != mNetworkAgent) return;
4652             ClientModeImpl.this.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot);
4653         }
4654 
4655         @Override
onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)4656         public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
4657             if (this != mNetworkAgent) return;
4658             // 0. If there are no thresholds, or if the thresholds are invalid,
4659             //    stop RSSI monitoring.
4660             // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
4661             //    MAX_VALUE at the start/end of the thresholds array if necessary.
4662             // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
4663             //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
4664             //    re-arm the hardware event. This needs to be done on the state machine thread to
4665             //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
4666             //    sent in the NetworkCapabilities) must be the one received from the hardware event
4667             //    received, or we might skip callbacks.
4668             // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
4669             logd("Received signal strength thresholds: " + Arrays.toString(thresholds));
4670             if (thresholds.length == 0) {
4671                 ClientModeImpl.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
4672                         mWifiInfo.getRssi());
4673                 return;
4674             }
4675             int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
4676             rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
4677             rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
4678             Arrays.sort(rssiVals);
4679             byte[] rssiRange = new byte[rssiVals.length];
4680             for (int i = 0; i < rssiVals.length; i++) {
4681                 int val = rssiVals[i];
4682                 if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
4683                     rssiRange[i] = (byte) val;
4684                 } else {
4685                     Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
4686                             + Arrays.toString(rssiVals));
4687                     ClientModeImpl.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
4688                             mWifiInfo.getRssi());
4689                     return;
4690                 }
4691             }
4692             // TODO: Do we quash rssi values in this sorted array which are very close?
4693             mRssiRanges = rssiRange;
4694             ClientModeImpl.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
4695                     mWifiInfo.getRssi());
4696         }
4697 
4698         @Override
onAutomaticReconnectDisabled()4699         public void onAutomaticReconnectDisabled() {
4700             if (this != mNetworkAgent) return;
4701             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
4702         }
4703     }
4704 
unwantedNetwork(int reason)4705     void unwantedNetwork(int reason) {
4706         sendMessage(CMD_UNWANTED_NETWORK, reason);
4707     }
4708 
doNetworkStatus(int status)4709     void doNetworkStatus(int status) {
4710         sendMessage(CMD_NETWORK_STATUS, status);
4711     }
4712 
4713     class L2ConnectedState extends State {
4714         class RssiEventHandler implements WifiNative.WifiRssiEventHandler {
4715             @Override
onRssiThresholdBreached(byte curRssi)4716             public void onRssiThresholdBreached(byte curRssi) {
4717                 if (mVerboseLoggingEnabled) {
4718                     Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi);
4719                 }
4720                 sendMessage(CMD_RSSI_THRESHOLD_BREACHED, curRssi);
4721             }
4722         }
4723 
4724         RssiEventHandler mRssiEventHandler = new RssiEventHandler();
4725 
4726         @Override
enter()4727         public void enter() {
4728             mRssiPollToken++;
4729             if (mEnableRssiPolling) {
4730                 mLinkProbeManager.resetOnNewConnection();
4731                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
4732             }
4733             sendNetworkChangeBroadcast(DetailedState.CONNECTING);
4734 
4735             // If this network was explicitly selected by the user, evaluate whether to inform
4736             // ConnectivityService of that fact so the system can treat it appropriately.
4737             final WifiConfiguration config = getCurrentWifiConfiguration();
4738 
4739             boolean explicitlySelected = false;
4740             if (shouldEvaluateWhetherToSendExplicitlySelected(config)) {
4741                 // If explicitlySelected is true, the network was selected by the user via Settings
4742                 // or QuickSettings. If this network has Internet access, switch to it. Otherwise,
4743                 // switch to it only if the user confirms that they really want to switch, or has
4744                 // already confirmed and selected "Don't ask again".
4745                 explicitlySelected =
4746                         mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid);
4747                 if (mVerboseLoggingEnabled) {
4748                     log("Network selected by UID " + config.lastConnectUid + " explicitlySelected="
4749                             + explicitlySelected);
4750                 }
4751             }
4752 
4753             if (mVerboseLoggingEnabled) {
4754                 log("explicitlySelected=" + explicitlySelected + " acceptUnvalidated="
4755                         + config.noInternetAccessExpected);
4756             }
4757 
4758             final NetworkAgentConfig naConfig = new NetworkAgentConfig.Builder()
4759                     .setLegacyType(ConnectivityManager.TYPE_WIFI)
4760                     .setLegacyTypeName(NETWORKTYPE)
4761                     .setExplicitlySelected(explicitlySelected)
4762                     .setUnvalidatedConnectivityAcceptable(
4763                             explicitlySelected && config.noInternetAccessExpected)
4764                     .setPartialConnectivityAcceptable(config.noInternetAccessExpected)
4765                     .build();
4766             final NetworkCapabilities nc = getCapabilities(getCurrentWifiConfiguration());
4767             // This should never happen.
4768             if (mNetworkAgent != null) {
4769                 Log.wtf(TAG, "mNetworkAgent is not null: " + mNetworkAgent);
4770                 mNetworkAgent.unregister();
4771             }
4772             mNetworkAgent = new WifiNetworkAgent(mContext, getHandler().getLooper(),
4773                     "WifiNetworkAgent", nc, mLinkProperties, 60, naConfig,
4774                     mNetworkFactory.getProvider());
4775             mWifiScoreReport.setNetworkAgent(mNetworkAgent);
4776 
4777             // We must clear the config BSSID, as the wifi chipset may decide to roam
4778             // from this point on and having the BSSID specified in the network block would
4779             // cause the roam to faile and the device to disconnect
4780             clearTargetBssid("L2ConnectedState");
4781             mCountryCode.setReadyForChange(false);
4782             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
4783             mWifiScoreCard.noteNetworkAgentCreated(mWifiInfo,
4784                     mNetworkAgent.getNetwork().getNetId());
4785             mBssidBlocklistMonitor.handleBssidConnectionSuccess(mLastBssid, mWifiInfo.getSSID());
4786         }
4787 
4788         @Override
exit()4789         public void exit() {
4790             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
4791             // Bug: 15347363
4792             // For paranoia's sake, call handleNetworkDisconnect
4793             // only if BSSID is null or last networkId
4794             // is not invalid.
4795             if (mVerboseLoggingEnabled) {
4796                 StringBuilder sb = new StringBuilder();
4797                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
4798                 if (mLastBssid != null) {
4799                     sb.append(" ").append(mLastBssid);
4800                 }
4801             }
4802             mCountryCode.setReadyForChange(true);
4803             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
4804             mWifiStateTracker.updateState(WifiStateTracker.DISCONNECTED);
4805             //Inform WifiLockManager
4806             WifiLockManager wifiLockManager = mWifiInjector.getWifiLockManager();
4807             wifiLockManager.updateWifiClientConnected(false);
4808         }
4809 
4810         @Override
processMessage(Message message)4811         public boolean processMessage(Message message) {
4812             boolean handleStatus = HANDLED;
4813             int callbackIdentifier = -1;
4814 
4815             switch (message.what) {
4816                 case CMD_PRE_DHCP_ACTION:
4817                     handlePreDhcpSetup();
4818                     break;
4819                 case CMD_PRE_DHCP_ACTION_COMPLETE:
4820                     if (mIpClient != null) {
4821                         mIpClient.completedPreDhcpAction();
4822                     }
4823                     break;
4824                 case CMD_POST_DHCP_ACTION:
4825                     handlePostDhcpSetup();
4826                     // We advance to mConnectedState because IpClient will also send a
4827                     // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
4828                     // which calls updateLinkProperties, which then sends
4829                     // CMD_IP_CONFIGURATION_SUCCESSFUL.
4830                     //
4831                     // In the event of failure, we transition to mDisconnectingState
4832                     // similarly--via messages sent back from IpClient.
4833                     break;
4834                 case CMD_IPV4_PROVISIONING_SUCCESS: {
4835                     handleIPv4Success((DhcpResultsParcelable) message.obj);
4836                     break;
4837                 }
4838                 case CMD_IPV4_PROVISIONING_FAILURE: {
4839                     handleIPv4Failure();
4840                     mWifiInjector.getWifiLastResortWatchdog()
4841                             .noteConnectionFailureAndTriggerIfNeeded(
4842                                     getTargetSsid(),
4843                                     (mLastBssid == null) ? mTargetBssid : mLastBssid,
4844                                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
4845                     break;
4846                 }
4847                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
4848                     if (getCurrentWifiConfiguration() == null) {
4849                         // The current config may have been removed while we were connecting,
4850                         // trigger a disconnect to clear up state.
4851                         reportConnectionAttemptEnd(
4852                                 WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
4853                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
4854                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
4855                         mWifiNative.disconnect(mInterfaceName);
4856                         transitionTo(mDisconnectingState);
4857                     } else {
4858                         handleSuccessfulIpConfiguration();
4859                         sendConnectedState();
4860                         transitionTo(mConnectedState);
4861                     }
4862                     break;
4863                 case CMD_IP_CONFIGURATION_LOST:
4864                     // Get Link layer stats so that we get fresh tx packet counters.
4865                     getWifiLinkLayerStats();
4866                     handleIpConfigurationLost();
4867                     reportConnectionAttemptEnd(
4868                             WifiMetrics.ConnectionEvent.FAILURE_DHCP,
4869                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
4870                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
4871                     mWifiInjector.getWifiLastResortWatchdog()
4872                             .noteConnectionFailureAndTriggerIfNeeded(
4873                                     getTargetSsid(),
4874                                     (mLastBssid == null) ? mTargetBssid : mLastBssid,
4875                                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
4876                     transitionTo(mDisconnectingState);
4877                     break;
4878                 case CMD_IP_REACHABILITY_LOST:
4879                     if (mVerboseLoggingEnabled && message.obj != null) log((String) message.obj);
4880                     mWifiDiagnostics.captureBugReportData(
4881                             WifiDiagnostics.REPORT_REASON_REACHABILITY_LOST);
4882                     mWifiMetrics.logWifiIsUnusableEvent(
4883                             WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST);
4884                     mWifiMetrics.addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_BAD,
4885                             WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST, -1);
4886                     if (mIpReachabilityDisconnectEnabled) {
4887                         handleIpReachabilityLost();
4888                         transitionTo(mDisconnectingState);
4889                     } else {
4890                         logd("CMD_IP_REACHABILITY_LOST but disconnect disabled -- ignore");
4891                     }
4892                     break;
4893                 case CMD_DISCONNECT:
4894                     mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
4895                             StaEvent.DISCONNECT_GENERIC);
4896                     mWifiNative.disconnect(mInterfaceName);
4897                     transitionTo(mDisconnectingState);
4898                     break;
4899                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4900                     if (message.arg1 == 1) {
4901                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
4902                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
4903                         mWifiNative.disconnect(mInterfaceName);
4904                         mTemporarilyDisconnectWifi = true;
4905                         transitionTo(mDisconnectingState);
4906                     }
4907                     break;
4908                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
4909                 case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT:
4910                     mWifiInfo.setBSSID((String) message.obj);
4911                     mLastNetworkId = message.arg1;
4912                     mWifiInfo.setNetworkId(mLastNetworkId);
4913                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
4914                     if (!mLastBssid.equals(message.obj)) {
4915                         mLastBssid = (String) message.obj;
4916                     }
4917                     break;
4918                 case CMD_ONESHOT_RSSI_POLL:
4919                     if (!mEnableRssiPolling) {
4920                         updateLinkLayerStatsRssiAndScoreReportInternal();
4921                     }
4922                     break;
4923                 case CMD_RSSI_POLL:
4924                     if (message.arg1 == mRssiPollToken) {
4925                         WifiLinkLayerStats stats = updateLinkLayerStatsRssiAndScoreReportInternal();
4926                         mWifiMetrics.updateWifiUsabilityStatsEntries(mWifiInfo, stats);
4927                         if (mWifiScoreReport.shouldCheckIpLayer()) {
4928                             if (mIpClient != null) {
4929                                 mIpClient.confirmConfiguration();
4930                             }
4931                             mWifiScoreReport.noteIpCheck();
4932                         }
4933                         int statusDataStall = mWifiDataStall.checkDataStallAndThroughputSufficiency(
4934                                 mLastLinkLayerStats, stats, mWifiInfo);
4935                         if (mDataStallTriggerTimeMs == -1
4936                                 && statusDataStall != WifiIsUnusableEvent.TYPE_UNKNOWN) {
4937                             mDataStallTriggerTimeMs = mClock.getElapsedSinceBootMillis();
4938                             mLastStatusDataStall = statusDataStall;
4939                         }
4940                         if (mDataStallTriggerTimeMs != -1) {
4941                             long elapsedTime =  mClock.getElapsedSinceBootMillis()
4942                                     - mDataStallTriggerTimeMs;
4943                             if (elapsedTime >= DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS) {
4944                                 mDataStallTriggerTimeMs = -1;
4945                                 mWifiMetrics.addToWifiUsabilityStatsList(
4946                                         WifiUsabilityStats.LABEL_BAD,
4947                                         convertToUsabilityStatsTriggerType(mLastStatusDataStall),
4948                                         -1);
4949                                 mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
4950                             }
4951                         }
4952                         mWifiMetrics.incrementWifiLinkLayerUsageStats(stats);
4953                         mLastLinkLayerStats = stats;
4954                         mWifiScoreCard.noteSignalPoll(mWifiInfo);
4955                         mLinkProbeManager.updateConnectionStats(
4956                                 mWifiInfo, mInterfaceName);
4957                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
4958                                 getPollRssiIntervalMsecs());
4959                         if (mVerboseLoggingEnabled) sendRssiChangeBroadcast(mWifiInfo.getRssi());
4960                         mWifiTrafficPoller.notifyOnDataActivity(mWifiInfo.txSuccess,
4961                                 mWifiInfo.rxSuccess);
4962                     } else {
4963                         // Polling has completed
4964                     }
4965                     break;
4966                 case CMD_ENABLE_RSSI_POLL:
4967                     cleanWifiScore();
4968                     mEnableRssiPolling = (message.arg1 == 1);
4969                     mRssiPollToken++;
4970                     if (mEnableRssiPolling) {
4971                         // First poll
4972                         mLastSignalLevel = -1;
4973                         mLinkProbeManager.resetOnScreenTurnedOn();
4974                         fetchRssiLinkSpeedAndFrequencyNative();
4975                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
4976                                 getPollRssiIntervalMsecs());
4977                     }
4978                     break;
4979                 case WifiMonitor.ASSOCIATED_BSSID_EVENT:
4980                     if ((String) message.obj == null) {
4981                         logw("Associated command w/o BSSID");
4982                         break;
4983                     }
4984                     mLastBssid = (String) message.obj;
4985                     if (mLastBssid != null && (mWifiInfo.getBSSID() == null
4986                             || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
4987                         mWifiInfo.setBSSID(mLastBssid);
4988                         WifiConfiguration config = getCurrentWifiConfiguration();
4989                         if (config != null) {
4990                             ScanDetailCache scanDetailCache = mWifiConfigManager
4991                                     .getScanDetailCacheForNetwork(config.networkId);
4992                             if (scanDetailCache != null) {
4993                                 ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
4994                                 if (scanResult != null) {
4995                                     mWifiInfo.setFrequency(scanResult.frequency);
4996                                 }
4997                             }
4998                         }
4999                     }
5000                     break;
5001                 case CMD_START_RSSI_MONITORING_OFFLOAD:
5002                 case CMD_RSSI_THRESHOLD_BREACHED:
5003                     byte currRssi = (byte) message.arg1;
5004                     processRssiThreshold(currRssi, message.what, mRssiEventHandler);
5005                     break;
5006                 case CMD_STOP_RSSI_MONITORING_OFFLOAD:
5007                     stopRssiMonitoringOffload();
5008                     break;
5009                 case CMD_RECONNECT:
5010                     log(" Ignore CMD_RECONNECT request because wifi is already connected");
5011                     break;
5012                 case CMD_RESET_SIM_NETWORKS:
5013                     if (message.arg1 != RESET_SIM_REASON_SIM_INSERTED
5014                             && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5015                         WifiConfiguration config =
5016                                 mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
5017                         if ((message.arg1 == RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED
5018                                 && config.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID)
5019                                 || (config.enterpriseConfig != null
5020                                         && config.enterpriseConfig.isAuthenticationSimBased()
5021                                         && !mWifiCarrierInfoManager.isSimPresent(mLastSubId))) {
5022                             mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5023                                     StaEvent.DISCONNECT_RESET_SIM_NETWORKS);
5024                             // remove local PMKSA cache in framework
5025                             mWifiNative.removeNetworkCachedData(mLastNetworkId);
5026                             // remove network so that supplicant's PMKSA cache is cleared
5027                             mWifiNative.removeAllNetworks(mInterfaceName);
5028                             mSimRequiredNotifier.showSimRequiredNotification(
5029                                     config, mLastSimBasedConnectionCarrierName);
5030                             transitionTo(mDisconnectingState);
5031                         }
5032                     }
5033                     /* allow parent state to reset data for other networks */
5034                     handleStatus = NOT_HANDLED;
5035                     break;
5036                 case CMD_START_IP_PACKET_OFFLOAD: {
5037                     int slot = message.arg1;
5038                     int intervalSeconds = message.arg2;
5039                     KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
5040                     int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
5041                     if (mNetworkAgent != null) {
5042                         mNetworkAgent.sendSocketKeepaliveEvent(slot, result);
5043                     }
5044                     break;
5045                 }
5046                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
5047                     if (mIpClient != null) {
5048                         final int slot = message.arg1;
5049                         if (message.obj instanceof NattKeepalivePacketData) {
5050                             final NattKeepalivePacketData pkt =
5051                                     (NattKeepalivePacketData) message.obj;
5052                             mIpClient.addKeepalivePacketFilter(slot, pkt);
5053                         } else if (message.obj instanceof TcpKeepalivePacketData) {
5054                             final TcpKeepalivePacketData pkt =
5055                                     (TcpKeepalivePacketData) message.obj;
5056                             mIpClient.addKeepalivePacketFilter(slot, pkt);
5057                         }
5058                     }
5059                     break;
5060                 }
5061                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
5062                     if (mIpClient != null) {
5063                         mIpClient.removeKeepalivePacketFilter(message.arg1);
5064                     }
5065                     break;
5066                 }
5067                 default:
5068                     handleStatus = NOT_HANDLED;
5069                     break;
5070             }
5071 
5072             if (handleStatus == HANDLED) {
5073                 logStateAndMessage(message, this);
5074             }
5075 
5076             return handleStatus;
5077         }
5078 
5079         /**
5080          * Fetches link stats and updates Wifi Score Report.
5081          */
updateLinkLayerStatsRssiAndScoreReportInternal()5082         private WifiLinkLayerStats updateLinkLayerStatsRssiAndScoreReportInternal() {
5083             WifiLinkLayerStats stats = getWifiLinkLayerStats();
5084             // Get Info and continue polling
5085             fetchRssiLinkSpeedAndFrequencyNative();
5086             // Send the update score to network agent.
5087             mWifiScoreReport.calculateAndReportScore();
5088             return stats;
5089         }
5090     }
5091 
5092     /**
5093      * Fetches link stats and updates Wifi Score Report.
5094      */
updateLinkLayerStatsRssiAndScoreReport()5095     public void updateLinkLayerStatsRssiAndScoreReport() {
5096         sendMessage(CMD_ONESHOT_RSSI_POLL);
5097     }
5098 
convertToUsabilityStatsTriggerType(int unusableEventTriggerType)5099     private static int convertToUsabilityStatsTriggerType(int unusableEventTriggerType) {
5100         int triggerType;
5101         switch (unusableEventTriggerType) {
5102             case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
5103                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_BAD_TX;
5104                 break;
5105             case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
5106                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_TX_WITHOUT_RX;
5107                 break;
5108             case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
5109                 triggerType = WifiUsabilityStats.TYPE_DATA_STALL_BOTH;
5110                 break;
5111             case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
5112                 triggerType = WifiUsabilityStats.TYPE_FIRMWARE_ALERT;
5113                 break;
5114             case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST:
5115                 triggerType = WifiUsabilityStats.TYPE_IP_REACHABILITY_LOST;
5116                 break;
5117             default:
5118                 triggerType = WifiUsabilityStats.TYPE_UNKNOWN;
5119                 Log.e(TAG, "Unknown WifiIsUnusableEvent: " + unusableEventTriggerType);
5120         }
5121         return triggerType;
5122     }
5123 
5124     class ObtainingIpState extends State {
5125         @Override
enter()5126         public void enter() {
5127             WifiConfiguration currentConfig = getCurrentWifiConfiguration();
5128             if (mIpClientWithPreConnection && mIpClient != null) {
5129                 mIpClient.notifyPreconnectionComplete(mSentHLPs);
5130                 mIpClientWithPreConnection = false;
5131                 mSentHLPs = false;
5132             } else {
5133                 startIpClient(currentConfig, false);
5134             }
5135             // Get Link layer stats so as we get fresh tx packet counters
5136             getWifiLinkLayerStats();
5137         }
5138 
5139         @Override
processMessage(Message message)5140         public boolean processMessage(Message message) {
5141             boolean handleStatus = HANDLED;
5142 
5143             switch(message.what) {
5144                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5145                     reportConnectionAttemptEnd(
5146                             WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
5147                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
5148                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5149                     mWifiInjector.getWifiLastResortWatchdog()
5150                             .noteConnectionFailureAndTriggerIfNeeded(
5151                                     getTargetSsid(),
5152                                     (message.obj == null)
5153                                     ? mTargetBssid : (String) message.obj,
5154                                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
5155                     handleStatus = NOT_HANDLED;
5156                     break;
5157                 case CMD_SET_HIGH_PERF_MODE:
5158                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5159                     deferMessage(message);
5160                     break;
5161                 default:
5162                     handleStatus = NOT_HANDLED;
5163                     break;
5164             }
5165 
5166             if (handleStatus == HANDLED) {
5167                 logStateAndMessage(message, this);
5168             }
5169             return handleStatus;
5170         }
5171     }
5172 
5173     /**
5174      * Helper function to check if we need to invoke
5175      * {@link NetworkAgent#explicitlySelected(boolean, boolean)} to indicate that we connected to a
5176      * network which the user just chose
5177      * (i.e less than {@link #LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS) before).
5178      */
5179     @VisibleForTesting
shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration currentConfig)5180     public boolean shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration currentConfig) {
5181         if (currentConfig == null) {
5182             Log.wtf(TAG, "Current WifiConfiguration is null, but IP provisioning just succeeded");
5183             return false;
5184         }
5185         long currentTimeMillis = mClock.getElapsedSinceBootMillis();
5186         return (mWifiConfigManager.getLastSelectedNetwork() == currentConfig.networkId
5187                 && currentTimeMillis - mWifiConfigManager.getLastSelectedTimeStamp()
5188                 < LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS);
5189     }
5190 
sendConnectedState()5191     private void sendConnectedState() {
5192         mNetworkAgent.markConnected();
5193         sendNetworkChangeBroadcast(DetailedState.CONNECTED);
5194     }
5195 
5196     class RoamingState extends State {
5197         boolean mAssociated;
5198         @Override
enter()5199         public void enter() {
5200             if (mVerboseLoggingEnabled) {
5201                 log("RoamingState Enter mScreenOn=" + mScreenOn);
5202             }
5203 
5204             // Make sure we disconnect if roaming fails
5205             mRoamWatchdogCount++;
5206             logd("Start Roam Watchdog " + mRoamWatchdogCount);
5207             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
5208                     mRoamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
5209             mAssociated = false;
5210         }
5211         @Override
processMessage(Message message)5212         public boolean processMessage(Message message) {
5213             WifiConfiguration config;
5214             boolean handleStatus = HANDLED;
5215 
5216             switch (message.what) {
5217                 case CMD_IP_CONFIGURATION_LOST:
5218                     config = getCurrentWifiConfiguration();
5219                     if (config != null) {
5220                         mWifiDiagnostics.captureBugReportData(
5221                                 WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
5222                     }
5223                     handleStatus = NOT_HANDLED;
5224                     break;
5225                 case CMD_UNWANTED_NETWORK:
5226                     if (mVerboseLoggingEnabled) {
5227                         log("Roaming and CS doesn't want the network -> ignore");
5228                     }
5229                     break;
5230                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5231                     /**
5232                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
5233                      * before NETWORK_DISCONNECTION_EVENT
5234                      * And there is an associated BSSID corresponding to our target BSSID, then
5235                      * we have missed the network disconnection, transition to mDisconnectedState
5236                      * and handle the rest of the events there.
5237                      */
5238                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5239                     if (stateChangeResult.state == SupplicantState.DISCONNECTED
5240                             || stateChangeResult.state == SupplicantState.INACTIVE
5241                             || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
5242                         if (mVerboseLoggingEnabled) {
5243                             log("STATE_CHANGE_EVENT in roaming state "
5244                                     + stateChangeResult.toString());
5245                         }
5246                         if (stateChangeResult.BSSID != null
5247                                 && stateChangeResult.BSSID.equals(mTargetBssid)) {
5248                             handleNetworkDisconnect();
5249                             transitionTo(mDisconnectedState);
5250                         }
5251                     }
5252                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
5253                         // We completed the layer2 roaming part
5254                         mAssociated = true;
5255                         if (stateChangeResult.BSSID != null) {
5256                             mTargetBssid = stateChangeResult.BSSID;
5257                         }
5258                     }
5259                     break;
5260                 case CMD_ROAM_WATCHDOG_TIMER:
5261                     if (mRoamWatchdogCount == message.arg1) {
5262                         if (mVerboseLoggingEnabled) log("roaming watchdog! -> disconnect");
5263                         mWifiMetrics.endConnectionEvent(
5264                                 WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
5265                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
5266                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5267                         mRoamFailCount++;
5268                         handleNetworkDisconnect();
5269                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5270                                 StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER);
5271                         mWifiNative.disconnect(mInterfaceName);
5272                         transitionTo(mDisconnectedState);
5273                     }
5274                     break;
5275                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5276                     if (mAssociated) {
5277                         if (mVerboseLoggingEnabled) {
5278                             log("roaming and Network connection established");
5279                         }
5280                         mLastNetworkId = message.arg1;
5281                         mLastBssid = (String) message.obj;
5282                         mWifiInfo.setBSSID(mLastBssid);
5283                         mWifiInfo.setNetworkId(mLastNetworkId);
5284 
5285                         // Successful framework roam! (probably)
5286                         mBssidBlocklistMonitor.handleBssidConnectionSuccess(mLastBssid,
5287                                 mWifiInfo.getSSID());
5288                         reportConnectionAttemptEnd(
5289                                 WifiMetrics.ConnectionEvent.FAILURE_NONE,
5290                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
5291                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5292 
5293                         // We must clear the config BSSID, as the wifi chipset may decide to roam
5294                         // from this point on and having the BSSID specified by QNS would cause
5295                         // the roam to fail and the device to disconnect.
5296                         // When transition from RoamingState to DisconnectingState or
5297                         // DisconnectedState, the config BSSID is cleared by
5298                         // handleNetworkDisconnect().
5299                         clearTargetBssid("RoamingCompleted");
5300 
5301                         // We used to transition to ObtainingIpState in an
5302                         // attempt to do DHCPv4 RENEWs on framework roams.
5303                         // DHCP can take too long to time out, and we now rely
5304                         // upon IpClient's use of IpReachabilityMonitor to
5305                         // confirm our current network configuration.
5306                         //
5307                         // mIpClient.confirmConfiguration() is called within
5308                         // the handling of SupplicantState.COMPLETED.
5309                         transitionTo(mConnectedState);
5310                     } else {
5311                         mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5312                     }
5313                     break;
5314                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5315                     // Throw away but only if it corresponds to the network we're roaming to
5316                     String bssid = (String) message.obj;
5317                     if (true) {
5318                         String target = "";
5319                         if (mTargetBssid != null) target = mTargetBssid;
5320                         log("NETWORK_DISCONNECTION_EVENT in roaming state"
5321                                 + " BSSID=" + bssid
5322                                 + " target=" + target);
5323                     }
5324                     clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
5325                     if (bssid != null && bssid.equals(mTargetBssid)) {
5326                         handleNetworkDisconnect();
5327                         transitionTo(mDisconnectedState);
5328                     }
5329                     break;
5330                 case CMD_GET_CURRENT_NETWORK:
5331                     replyToMessage(message, message.what, getCurrentNetwork());
5332                     break;
5333                 default:
5334                     handleStatus = NOT_HANDLED;
5335                     break;
5336             }
5337 
5338             if (handleStatus == HANDLED) {
5339                 logStateAndMessage(message, this);
5340             }
5341             return handleStatus;
5342         }
5343 
5344         @Override
exit()5345         public void exit() {
5346             logd("ClientModeImpl: Leaving Roaming state");
5347         }
5348     }
5349 
5350     class ConnectedState extends State {
5351         @Override
enter()5352         public void enter() {
5353             if (mVerboseLoggingEnabled) {
5354                 log("Enter ConnectedState  mScreenOn=" + mScreenOn);
5355             }
5356 
5357             reportConnectionAttemptEnd(
5358                     WifiMetrics.ConnectionEvent.FAILURE_NONE,
5359                     WifiMetricsProto.ConnectionEvent.HLF_NONE,
5360                     WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5361             mWifiConnectivityManager.handleConnectionStateChanged(
5362                     WifiConnectivityManager.WIFI_STATE_CONNECTED);
5363             registerConnected();
5364             mLastConnectAttemptTimestamp = 0;
5365             mTargetWifiConfiguration = null;
5366             mWifiScoreReport.reset();
5367             mLastSignalLevel = -1;
5368 
5369             // Not roaming anymore
5370             mIsAutoRoaming = false;
5371 
5372             mLastDriverRoamAttempt = 0;
5373             mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
5374             mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
5375             mWifiStateTracker.updateState(WifiStateTracker.CONNECTED);
5376             //Inform WifiLockManager
5377             WifiLockManager wifiLockManager = mWifiInjector.getWifiLockManager();
5378             wifiLockManager.updateWifiClientConnected(true);
5379             mWifiScoreReport.startConnectedNetworkScorer(mNetworkAgent.getNetwork().getNetId());
5380             updateLinkLayerStatsRssiAndScoreReport();
5381         }
5382         @Override
processMessage(Message message)5383         public boolean processMessage(Message message) {
5384             WifiConfiguration config = null;
5385             boolean handleStatus = HANDLED;
5386 
5387             switch (message.what) {
5388                 case CMD_UNWANTED_NETWORK:
5389                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
5390                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5391                                 StaEvent.DISCONNECT_UNWANTED);
5392                         mWifiNative.disconnect(mInterfaceName);
5393                         transitionTo(mDisconnectingState);
5394                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
5395                             || message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
5396                         Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
5397                                 ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
5398                                 : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
5399                         config = getCurrentWifiConfiguration();
5400                         if (config != null) {
5401                             // Disable autojoin
5402                             if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
5403                                 mWifiConfigManager.setNetworkValidatedInternetAccess(
5404                                         config.networkId, false);
5405                                 mWifiConfigManager.updateNetworkSelectionStatus(config.networkId,
5406                                         DISABLED_NO_INTERNET_PERMANENT);
5407                             } else {
5408                                 // stop collect last-mile stats since validation fail
5409                                 removeMessages(CMD_DIAGS_CONNECT_TIMEOUT);
5410                                 mWifiDiagnostics.reportConnectionEvent(
5411                                         WifiDiagnostics.CONNECTION_EVENT_FAILED);
5412                                 mWifiConfigManager.incrementNetworkNoInternetAccessReports(
5413                                         config.networkId);
5414                                 // If this was not the last selected network, update network
5415                                 // selection status to temporarily disable the network.
5416                                 if (mWifiConfigManager.getLastSelectedNetwork() != config.networkId
5417                                         && !config.noInternetAccessExpected) {
5418                                     Log.i(TAG, "Temporarily disabling network because of"
5419                                             + "no-internet access");
5420                                     mWifiConfigManager.updateNetworkSelectionStatus(
5421                                             config.networkId,
5422                                             DISABLED_NO_INTERNET_TEMPORARY);
5423                                 }
5424                                 int rssi = mWifiInfo.getRssi();
5425                                 int sufficientRssi = mWifiInjector.getScoringParams()
5426                                         .getSufficientRssi(mWifiInfo.getFrequency());
5427                                 boolean isLowRssi = rssi < sufficientRssi;
5428                                 mBssidBlocklistMonitor.handleBssidConnectionFailure(
5429                                         mLastBssid, config.SSID,
5430                                         BssidBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE,
5431                                         isLowRssi);
5432                                 mWifiScoreCard.noteValidationFailure(mWifiInfo);
5433                             }
5434                         }
5435                     }
5436                     break;
5437                 case CMD_NETWORK_STATUS:
5438                     if (message.arg1 == NetworkAgent.VALIDATION_STATUS_VALID) {
5439                         // stop collect last-mile stats since validation pass
5440                         removeMessages(CMD_DIAGS_CONNECT_TIMEOUT);
5441                         mWifiDiagnostics.reportConnectionEvent(
5442                                 WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED);
5443                         mWifiScoreCard.noteValidationSuccess(mWifiInfo);
5444                         mBssidBlocklistMonitor.handleNetworkValidationSuccess(mLastBssid,
5445                                 mWifiInfo.getSSID());
5446                         config = getCurrentWifiConfiguration();
5447                         if (config != null) {
5448                             // re-enable autojoin
5449                             mWifiConfigManager.updateNetworkSelectionStatus(
5450                                     config.networkId,
5451                                     WifiConfiguration.NetworkSelectionStatus
5452                                             .DISABLED_NONE);
5453                             mWifiConfigManager.setNetworkValidatedInternetAccess(
5454                                     config.networkId, true);
5455                         }
5456                     }
5457                     break;
5458                 case CMD_ACCEPT_UNVALIDATED:
5459                     boolean accept = (message.arg1 != 0);
5460                     mWifiConfigManager.setNetworkNoInternetAccessExpected(mLastNetworkId, accept);
5461                     break;
5462                 case WifiMonitor.ASSOCIATED_BSSID_EVENT:
5463                     // ASSOCIATING to a new BSSID while already connected, indicates
5464                     // that driver is roaming
5465                     mLastDriverRoamAttempt = mClock.getWallClockMillis();
5466                     handleStatus = NOT_HANDLED;
5467                     break;
5468                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5469                     long lastRoam = 0;
5470                     reportConnectionAttemptEnd(
5471                             WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
5472                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
5473                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5474                     if (mLastDriverRoamAttempt != 0) {
5475                         // Calculate time since last driver roam attempt
5476                         lastRoam = mClock.getWallClockMillis() - mLastDriverRoamAttempt;
5477                         mLastDriverRoamAttempt = 0;
5478                     }
5479                     if (unexpectedDisconnectedReason(message.arg2)) {
5480                         mWifiDiagnostics.captureBugReportData(
5481                                 WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
5482                     }
5483 
5484                     boolean localGen = message.arg1 == 1;
5485                     if (!localGen) { // ignore disconnects initiated by wpa_supplicant.
5486                         mWifiScoreCard.noteNonlocalDisconnect(message.arg2);
5487                         int rssi = mWifiInfo.getRssi();
5488                         int sufficientRssi = mWifiInjector.getScoringParams()
5489                                 .getSufficientRssi(mWifiInfo.getFrequency());
5490                         boolean isLowRssi = rssi < sufficientRssi;
5491                         mBssidBlocklistMonitor.handleBssidConnectionFailure(mWifiInfo.getBSSID(),
5492                                 mWifiInfo.getSSID(),
5493                                 BssidBlocklistMonitor.REASON_ABNORMAL_DISCONNECT, isLowRssi);
5494                     }
5495                     config = getCurrentWifiConfiguration();
5496 
5497                     if (mVerboseLoggingEnabled) {
5498                         log("NETWORK_DISCONNECTION_EVENT in connected state"
5499                                 + " BSSID=" + mWifiInfo.getBSSID()
5500                                 + " RSSI=" + mWifiInfo.getRssi()
5501                                 + " freq=" + mWifiInfo.getFrequency()
5502                                 + " reason=" + message.arg2
5503                                 + " Network Selection Status=" + (config == null ? "Unavailable"
5504                                     : config.getNetworkSelectionStatus().getNetworkStatusString()));
5505                     }
5506                     break;
5507                 case CMD_START_ROAM:
5508                     // Clear the driver roam indication since we are attempting a framework roam
5509                     mLastDriverRoamAttempt = 0;
5510 
5511                     /* Connect command coming from auto-join */
5512                     int netId = message.arg1;
5513                     ScanResult candidate = (ScanResult) message.obj;
5514                     String bssid = SUPPLICANT_BSSID_ANY;
5515                     if (candidate != null) {
5516                         bssid = candidate.BSSID;
5517                     }
5518                     config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
5519                     if (config == null) {
5520                         loge("CMD_START_ROAM and no config, bail out...");
5521                         break;
5522                     }
5523                     int scanRssi = mWifiConfigManager.findScanRssi(netId,
5524                             mWifiHealthMonitor.getScanRssiValidTimeMs());
5525                     mWifiScoreCard.noteConnectionAttempt(mWifiInfo, scanRssi, config.SSID);
5526                     setTargetBssid(config, bssid);
5527                     mTargetNetworkId = netId;
5528 
5529                     logd("CMD_START_ROAM sup state "
5530                             + " my state " + getCurrentState().getName()
5531                             + " nid=" + Integer.toString(netId)
5532                             + " config " + config.getKey()
5533                             + " targetRoamBSSID " + mTargetBssid);
5534 
5535                     reportConnectionAttemptStart(config, mTargetBssid,
5536                             WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
5537                     if (mWifiNative.roamToNetwork(mInterfaceName, config)) {
5538                         mLastConnectAttemptTimestamp = mClock.getWallClockMillis();
5539                         mTargetWifiConfiguration = config;
5540                         mIsAutoRoaming = true;
5541                         mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_ROAM, config);
5542                         transitionTo(mRoamingState);
5543                     } else {
5544                         loge("CMD_START_ROAM Failed to start roaming to network " + config);
5545                         reportConnectionAttemptEnd(
5546                                 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5547                                 WifiMetricsProto.ConnectionEvent.HLF_NONE,
5548                                 WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
5549                         mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5550                         break;
5551                     }
5552                     break;
5553                 case CMD_IP_CONFIGURATION_LOST:
5554                     mWifiMetrics.incrementIpRenewalFailure();
5555                     handleStatus = NOT_HANDLED;
5556                     break;
5557                 case CMD_GET_CURRENT_NETWORK:
5558                     replyToMessage(message, message.what, getCurrentNetwork());
5559                     break;
5560                 default:
5561                     handleStatus = NOT_HANDLED;
5562                     break;
5563             }
5564 
5565             if (handleStatus == HANDLED) {
5566                 logStateAndMessage(message, this);
5567             }
5568 
5569             return handleStatus;
5570         }
5571 
5572         @Override
5573         public void exit() {
5574             logd("ClientModeImpl: Leaving Connected state");
5575             mWifiConnectivityManager.handleConnectionStateChanged(
5576                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
5577 
5578             mLastDriverRoamAttempt = 0;
5579             mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
5580         }
5581     }
5582 
5583     class DisconnectingState extends State {
5584 
5585         @Override
5586         public void enter() {
5587 
5588             if (mVerboseLoggingEnabled) {
5589                 logd(" Enter DisconnectingState State screenOn=" + mScreenOn);
5590             }
5591 
5592             // Make sure we disconnect: we enter this state prior to connecting to a new
5593             // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
5594             // event which in this case will be indicating that supplicant started to associate.
5595             // In some cases supplicant doesn't ignore the connect requests (it might not
5596             // find the target SSID in its cache),
5597             // Therefore we end up stuck that state, hence the need for the watchdog.
5598             mDisconnectingWatchdogCount++;
5599             logd("Start Disconnecting Watchdog " + mDisconnectingWatchdogCount);
5600             sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
5601                     mDisconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
5602         }
5603 
5604         @Override
5605         public boolean processMessage(Message message) {
5606             boolean handleStatus = HANDLED;
5607 
5608             switch (message.what) {
5609                 case CMD_CONNECT_NETWORK:
5610                 case CMD_SAVE_NETWORK:
5611                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5612                     deferMessage(message);
5613                     break;
5614                 case CMD_DISCONNECT:
5615                     if (mVerboseLoggingEnabled) {
5616                         log("Ignore CMD_DISCONNECT when already disconnecting.");
5617                     }
5618                     break;
5619                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5620                     if (mVerboseLoggingEnabled) {
5621                         log("Ignore NETWORK_CONNECTION_EVENT when already disconnecting.");
5622                     }
5623                     break;
5624                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
5625                     if (mDisconnectingWatchdogCount == message.arg1) {
5626                         if (mVerboseLoggingEnabled) log("disconnecting watchdog! -> disconnect");
5627                         handleNetworkDisconnect();
5628                         transitionTo(mDisconnectedState);
5629                     }
5630                     break;
5631                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5632                     /**
5633                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
5634                      * we have missed the network disconnection, transition to mDisconnectedState
5635                      * and handle the rest of the events there
5636                      */
5637                     mMessageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5638                     deferMessage(message);
5639                     handleNetworkDisconnect();
5640                     transitionTo(mDisconnectedState);
5641                     break;
5642                 default:
5643                     handleStatus = NOT_HANDLED;
5644                     break;
5645             }
5646 
5647             if (handleStatus == HANDLED) {
5648                 logStateAndMessage(message, this);
5649             }
5650             return handleStatus;
5651         }
5652     }
5653 
5654     class DisconnectedState extends State {
5655         @Override
5656         public void enter() {
5657             Log.i(TAG, "disconnectedstate enter");
5658             // We don't scan frequently if this is a temporary disconnect
5659             // due to p2p
5660             if (mTemporarilyDisconnectWifi) {
5661                 p2pSendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
5662                 return;
5663             }
5664 
5665             if (mVerboseLoggingEnabled) {
5666                 logd(" Enter DisconnectedState screenOn=" + mScreenOn);
5667             }
5668 
5669             /** clear the roaming state, if we were roaming, we failed */
5670             mIsAutoRoaming = false;
5671 
5672             mWifiConnectivityManager.handleConnectionStateChanged(
5673                     WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
5674         }
5675 
5676         @Override
5677         public boolean processMessage(Message message) {
5678             boolean handleStatus = HANDLED;
5679 
5680             switch (message.what) {
5681                 case CMD_DISCONNECT:
5682                     mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5683                             StaEvent.DISCONNECT_GENERIC);
5684                     mWifiNative.disconnect(mInterfaceName);
5685                     break;
5686                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5687                     stopIpClient();
5688                     if (message.arg2 == 15 /* FOURWAY_HANDSHAKE_TIMEOUT */) {
5689                         String bssid = (message.obj == null)
5690                                 ? mTargetBssid : (String) message.obj;
5691                         mWifiInjector.getWifiLastResortWatchdog()
5692                                 .noteConnectionFailureAndTriggerIfNeeded(
5693                                         getTargetSsid(), bssid,
5694                                         WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
5695                     }
5696                     clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
5697                     mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
5698                     break;
5699                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5700                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5701                     if (mVerboseLoggingEnabled) {
5702                         logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state
5703                                 + " -> state= "
5704                                 + WifiInfo.getDetailedStateOf(stateChangeResult.state));
5705                     }
5706                     if (SupplicantState.isConnecting(stateChangeResult.state)) {
5707                         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(
5708                                 stateChangeResult.networkId);
5709 
5710                         // Update Passpoint information before setNetworkDetailedState as
5711                         // WifiTracker monitors NETWORK_STATE_CHANGED_ACTION to update UI.
5712                         mWifiInfo.setFQDN(null);
5713                         mWifiInfo.setPasspointUniqueId(null);
5714                         mWifiInfo.setOsuAp(false);
5715                         mWifiInfo.setProviderFriendlyName(null);
5716                         if (config != null && (config.isPasspoint() || config.osu)) {
5717                             if (config.isPasspoint()) {
5718                                 mWifiInfo.setFQDN(config.FQDN);
5719                                 mWifiInfo.setPasspointUniqueId(config.getPasspointUniqueId());
5720                             } else {
5721                                 mWifiInfo.setOsuAp(true);
5722                             }
5723                             mWifiInfo.setProviderFriendlyName(config.providerFriendlyName);
5724                         }
5725                     }
5726                     sendNetworkChangeBroadcast(
5727                             WifiInfo.getDetailedStateOf(stateChangeResult.state));
5728                     /* ConnectModeState does the rest of the handling */
5729                     handleStatus = NOT_HANDLED;
5730                     break;
5731                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
5732                     NetworkInfo info = (NetworkInfo) message.obj;
5733                     mP2pConnected.set(info.isConnected());
5734                     break;
5735                 case CMD_RECONNECT:
5736                 case CMD_REASSOCIATE:
5737                     if (mTemporarilyDisconnectWifi) {
5738                         // Drop a third party reconnect/reassociate if STA is
5739                         // temporarily disconnected for p2p
5740                         break;
5741                     } else {
5742                         // ConnectModeState handles it
5743                         handleStatus = NOT_HANDLED;
5744                     }
5745                     break;
5746                 case CMD_SCREEN_STATE_CHANGED:
5747                     handleScreenStateChanged(message.arg1 != 0);
5748                     break;
5749                 default:
5750                     handleStatus = NOT_HANDLED;
5751                     break;
5752             }
5753 
5754             if (handleStatus == HANDLED) {
5755                 logStateAndMessage(message, this);
5756             }
5757             return handleStatus;
5758         }
5759 
5760         @Override
5761         public void exit() {
5762             mWifiConnectivityManager.handleConnectionStateChanged(
5763                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
5764         }
5765     }
5766 
5767     /**
5768      * State machine initiated requests can have replyTo set to null, indicating
5769      * there are no recipients, we ignore those reply actions.
5770      */
5771     private void replyToMessage(Message msg, int what) {
5772         if (msg.replyTo == null) return;
5773         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
5774         mReplyChannel.replyToMessage(msg, dstMsg);
5775     }
5776 
5777     private void replyToMessage(Message msg, int what, int arg1) {
5778         if (msg.replyTo == null) return;
5779         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
5780         dstMsg.arg1 = arg1;
5781         mReplyChannel.replyToMessage(msg, dstMsg);
5782     }
5783 
5784     private void replyToMessage(Message msg, int what, Object obj) {
5785         if (msg.replyTo == null) return;
5786         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
5787         dstMsg.obj = obj;
5788         mReplyChannel.replyToMessage(msg, dstMsg);
5789     }
5790 
5791     /**
5792      * arg2 on the source message has a unique id that needs to be retained in replies
5793      * to match the request
5794      * <p>see WifiManager for details
5795      */
5796     private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
5797         Message msg = Message.obtain();
5798         msg.what = what;
5799         msg.arg2 = srcMsg.arg2;
5800         return msg;
5801     }
5802 
5803     /**
5804      * Notify interested parties if a wifi config has been changed.
5805      *
5806      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
5807      * @param config Must have a WifiConfiguration object to succeed
5808      * TODO: b/35258354 investigate if this can be removed.  Is the broadcast sent by
5809      * WifiConfigManager sufficient?
5810      */
5811     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
5812             WifiConfiguration config) {
5813         Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
5814         if (config != null && config.SSID != null && mWifiPermissionsUtil.isLocationModeEnabled()) {
5815             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
5816         }
5817         intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE, wifiCredentialEventType);
5818         mContext.createContextAsUser(UserHandle.CURRENT, 0)
5819                 .sendBroadcastWithMultiplePermissions(
5820                         intent,
5821                         new String[]{
5822                                 android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE,
5823                                 android.Manifest.permission.ACCESS_FINE_LOCATION,
5824                         });
5825     }
5826 
5827     void handleGsmAuthRequest(SimAuthRequestData requestData) {
5828         if (mTargetWifiConfiguration != null
5829                 && mTargetWifiConfiguration.networkId
5830                 == requestData.networkId) {
5831             logd("id matches targetWifiConfiguration");
5832         } else if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
5833                 && mLastNetworkId == requestData.networkId) {
5834             logd("id matches currentWifiConfiguration");
5835         } else {
5836             logd("id does not match targetWifiConfiguration");
5837             return;
5838         }
5839 
5840         /*
5841          * Try authentication in the following order.
5842          *
5843          *    Standard       Cellular_auth     Type Command
5844          *
5845          * 1. 3GPP TS 31.102 3G_authentication [Length][RAND][Length][AUTN]
5846          *                            [Length][RES][Length][CK][Length][IK] and more
5847          * 2. 3GPP TS 31.102 2G_authentication [Length][RAND]
5848          *                            [Length][SRES][Length][Cipher Key Kc]
5849          * 3. 3GPP TS 11.11  2G_authentication [RAND]
5850          *                            [SRES][Cipher Key Kc]
5851          */
5852         String response = mWifiCarrierInfoManager
5853                 .getGsmSimAuthResponse(requestData.data, mTargetWifiConfiguration);
5854         if (response == null) {
5855             // In case of failure, issue may be due to sim type, retry as No.2 case
5856             response = mWifiCarrierInfoManager
5857                     .getGsmSimpleSimAuthResponse(requestData.data, mTargetWifiConfiguration);
5858             if (response == null) {
5859                 // In case of failure, issue may be due to sim type, retry as No.3 case
5860                 response = mWifiCarrierInfoManager.getGsmSimpleSimNoLengthAuthResponse(
5861                                 requestData.data, mTargetWifiConfiguration);
5862             }
5863         }
5864         if (response == null || response.length() == 0) {
5865             mWifiNative.simAuthFailedResponse(mInterfaceName);
5866         } else {
5867             logv("Supplicant Response -" + response);
5868             mWifiNative.simAuthResponse(
5869                     mInterfaceName, WifiNative.SIM_AUTH_RESP_TYPE_GSM_AUTH, response);
5870         }
5871     }
5872 
5873     void handle3GAuthRequest(SimAuthRequestData requestData) {
5874         if (mTargetWifiConfiguration != null
5875                 && mTargetWifiConfiguration.networkId
5876                 == requestData.networkId) {
5877             logd("id matches targetWifiConfiguration");
5878         } else if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
5879                 && mLastNetworkId == requestData.networkId) {
5880             logd("id matches currentWifiConfiguration");
5881         } else {
5882             logd("id does not match targetWifiConfiguration");
5883             return;
5884         }
5885 
5886         SimAuthResponseData response = mWifiCarrierInfoManager
5887                 .get3GAuthResponse(requestData, mTargetWifiConfiguration);
5888         if (response != null) {
5889             mWifiNative.simAuthResponse(
5890                     mInterfaceName, response.type, response.response);
5891         } else {
5892             mWifiNative.umtsAuthFailedResponse(mInterfaceName);
5893         }
5894     }
5895 
5896     /**
5897      * Automatically connect to the network specified
5898      *
5899      * @param networkId ID of the network to connect to
5900      * @param uid UID of the app triggering the connection.
5901      * @param bssid BSSID of the network
5902      */
5903     public void startConnectToNetwork(int networkId, int uid, String bssid) {
5904         sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
5905     }
5906 
5907     /**
5908      * Automatically roam to the network specified
5909      *
5910      * @param networkId ID of the network to roam to
5911      * @param scanResult scan result which identifies the network to roam to
5912      */
5913     public void startRoamToNetwork(int networkId, ScanResult scanResult) {
5914         sendMessage(CMD_START_ROAM, networkId, 0, scanResult);
5915     }
5916 
5917     /**
5918      * Dynamically turn on/off WifiConnectivityManager
5919      *
5920      * @param choice true-enable; false-disable
5921      */
5922     public void allowAutoJoinGlobal(boolean choice) {
5923         mWifiConnectivityManager.setAutoJoinEnabledExternal(choice);
5924     }
5925 
5926     /**
5927      * @param reason reason code from supplicant on network disconnected event
5928      * @return true if this is a suspicious disconnect
5929      */
5930     static boolean unexpectedDisconnectedReason(int reason) {
5931         return reason == 2              // PREV_AUTH_NOT_VALID
5932                 || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
5933                 || reason == 7          // FRAME_FROM_NONASSOC_STA
5934                 || reason == 8          // STA_HAS_LEFT
5935                 || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
5936                 || reason == 14         // MICHAEL_MIC_FAILURE
5937                 || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
5938                 || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
5939                 || reason == 18         // GROUP_CIPHER_NOT_VALID
5940                 || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
5941                 || reason == 23         // IEEE_802_1X_AUTH_FAILED
5942                 || reason == 34;        // DISASSOC_LOW_ACK
5943     }
5944 
5945     private static String getLinkPropertiesSummary(LinkProperties lp) {
5946         List<String> attributes = new ArrayList<>(6);
5947         if (lp.hasIpv4Address()) {
5948             attributes.add("v4");
5949         }
5950         if (lp.hasIpv4DefaultRoute()) {
5951             attributes.add("v4r");
5952         }
5953         if (lp.hasIpv4DnsServer()) {
5954             attributes.add("v4dns");
5955         }
5956         if (lp.hasGlobalIpv6Address()) {
5957             attributes.add("v6");
5958         }
5959         if (lp.hasIpv6DefaultRoute()) {
5960             attributes.add("v6r");
5961         }
5962         if (lp.hasIpv6DnsServer()) {
5963             attributes.add("v6dns");
5964         }
5965 
5966         return TextUtils.join(" ", attributes);
5967     }
5968 
5969     /**
5970      * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
5971      * This should match the network config framework is attempting to connect to.
5972      */
5973     private String getTargetSsid() {
5974         WifiConfiguration currentConfig = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
5975         if (currentConfig != null) {
5976             return currentConfig.SSID;
5977         }
5978         return null;
5979     }
5980 
5981     /**
5982      * Send message to WifiP2pServiceImpl.
5983      * @return true if message is sent.
5984      *         false if there is no channel configured for WifiP2pServiceImpl.
5985      */
5986     private boolean p2pSendMessage(int what) {
5987         if (mWifiP2pChannel != null) {
5988             mWifiP2pChannel.sendMessage(what);
5989             return true;
5990         }
5991         return false;
5992     }
5993 
5994     /**
5995      * Send message to WifiP2pServiceImpl with an additional param |arg1|.
5996      * @return true if message is sent.
5997      *         false if there is no channel configured for WifiP2pServiceImpl.
5998      */
5999     private boolean p2pSendMessage(int what, int arg1) {
6000         if (mWifiP2pChannel != null) {
6001             mWifiP2pChannel.sendMessage(what, arg1);
6002             return true;
6003         }
6004         return false;
6005     }
6006 
6007     /**
6008      * Check if there is any connection request for WiFi network.
6009      */
6010     private boolean hasConnectionRequests() {
6011         return mNetworkFactory.hasConnectionRequests()
6012                 || mUntrustedNetworkFactory.hasConnectionRequests();
6013     }
6014 
6015     /**
6016      * Returns whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
6017      */
6018     public boolean getIpReachabilityDisconnectEnabled() {
6019         return mIpReachabilityDisconnectEnabled;
6020     }
6021 
6022     /**
6023      * Sets whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
6024      */
6025     public void setIpReachabilityDisconnectEnabled(boolean enabled) {
6026         mIpReachabilityDisconnectEnabled = enabled;
6027     }
6028 
6029     /**
6030      * Sends a message to initialize the ClientModeImpl.
6031      */
6032     public void initialize() {
6033         sendMessage(CMD_INITIALIZE);
6034     }
6035 
6036     /**
6037      * Add a network request match callback to {@link WifiNetworkFactory}.
6038      */
6039     public void addNetworkRequestMatchCallback(IBinder binder,
6040                                                INetworkRequestMatchCallback callback,
6041                                                int callbackIdentifier) {
6042         mNetworkFactory.addCallback(binder, callback, callbackIdentifier);
6043     }
6044 
6045     /**
6046      * Remove a network request match callback from {@link WifiNetworkFactory}.
6047      */
6048     public void removeNetworkRequestMatchCallback(int callbackIdentifier) {
6049         mNetworkFactory.removeCallback(callbackIdentifier);
6050     }
6051 
6052     /**
6053      * Approve all access points from {@link WifiNetworkFactory} for the provided package.
6054      * Used by shell commands.
6055      */
6056     public void setNetworkRequestUserApprovedApp(@NonNull String packageName, boolean approved) {
6057         mNetworkFactory.setUserApprovedApp(packageName, approved);
6058     }
6059 
6060     /**
6061      * Whether all access points are approved for the specified app.
6062      * Used by shell commands.
6063      */
6064     public boolean hasNetworkRequestUserApprovedApp(@NonNull String packageName) {
6065         return mNetworkFactory.hasUserApprovedApp(packageName);
6066     }
6067 
6068     /**
6069      * Remove all approved access points from {@link WifiNetworkFactory} for the provided package.
6070      */
6071     public void removeNetworkRequestUserApprovedAccessPointsForApp(@NonNull String packageName) {
6072         mNetworkFactory.removeUserApprovedAccessPointsForApp(packageName);
6073     }
6074 
6075     /**
6076      * Clear all approved access points from {@link WifiNetworkFactory}.
6077      */
6078     public void clearNetworkRequestUserApprovedAccessPoints() {
6079         mNetworkFactory.clear();
6080     }
6081 
6082     /**
6083      * Gets the factory MAC address of wlan0 (station interface).
6084      * @return String representation of the factory MAC address.
6085      */
6086     public String getFactoryMacAddress() {
6087         MacAddress macAddress = mWifiNative.getFactoryMacAddress(mInterfaceName);
6088         if (macAddress != null) {
6089             return macAddress.toString();
6090         }
6091         if (!isConnectedMacRandomizationEnabled()) {
6092             return mWifiNative.getMacAddress(mInterfaceName);
6093         }
6094         return null;
6095     }
6096 
6097     /**
6098      * Sets the current device mobility state.
6099      * @param state the new device mobility state
6100      */
6101     public void setDeviceMobilityState(@DeviceMobilityState int state) {
6102         mWifiConnectivityManager.setDeviceMobilityState(state);
6103         mWifiHealthMonitor.setDeviceMobilityState(state);
6104         mWifiDataStall.setDeviceMobilityState(state);
6105     }
6106 
6107     /**
6108      * Updates the Wi-Fi usability score.
6109      * @param seqNum Sequence number of the Wi-Fi usability score.
6110      * @param score The Wi-Fi usability score.
6111      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score.
6112      */
6113     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
6114         mWifiMetrics.incrementWifiUsabilityScoreCount(seqNum, score, predictionHorizonSec);
6115     }
6116 
6117     /**
6118      * Sends a link probe.
6119      */
6120     @VisibleForTesting
6121     public void probeLink(WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
6122         mWifiNative.probeLink(mInterfaceName, MacAddress.fromString(mWifiInfo.getBSSID()),
6123                 callback, mcs);
6124     }
6125 
6126     private void sendActionListenerFailure(int callbackIdentifier, int reason) {
6127         IActionListener actionListener;
6128         synchronized (mProcessingActionListeners) {
6129             actionListener = mProcessingActionListeners.remove(callbackIdentifier);
6130         }
6131         if (actionListener != null) {
6132             try {
6133                 actionListener.onFailure(reason);
6134             } catch (RemoteException e) {
6135                 // no-op (client may be dead, nothing to be done)
6136             }
6137         }
6138     }
6139 
6140     private void sendActionListenerSuccess(int callbackIdentifier) {
6141         IActionListener actionListener;
6142         synchronized (mProcessingActionListeners) {
6143             actionListener = mProcessingActionListeners.remove(callbackIdentifier);
6144         }
6145         if (actionListener != null) {
6146             try {
6147                 actionListener.onSuccess();
6148             } catch (RemoteException e) {
6149                 // no-op (client may be dead, nothing to be done)
6150             }
6151         }
6152     }
6153 
6154     /**
6155      * Trigger network connection and provide status via the provided callback.
6156      */
6157     public void connect(WifiConfiguration config, int netId, @Nullable IBinder binder,
6158             @Nullable IActionListener callback, int callbackIdentifier, int callingUid) {
6159         mWifiInjector.getWifiThreadRunner().post(() -> {
6160             if (callback != null && binder != null) {
6161                 mProcessingActionListeners.add(binder, callback, callbackIdentifier);
6162             }
6163             /**
6164              * The connect message can contain a network id passed as arg1 on message or
6165              * or a config passed as obj on message.
6166              * For a new network, a config is passed to create and connect.
6167              * For an existing network, a network id is passed
6168              */
6169             NetworkUpdateResult result = null;
6170             if (config != null) {
6171                 result = mWifiConfigManager.addOrUpdateNetwork(config, callingUid);
6172                 if (!result.isSuccess()) {
6173                     loge("connectNetwork adding/updating config=" + config + " failed");
6174                     sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6175                     return;
6176                 }
6177                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6178             } else {
6179                 if (mWifiConfigManager.getConfiguredNetwork(netId) == null) {
6180                     loge("connectNetwork Invalid network Id=" + netId);
6181                     sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6182                     return;
6183                 }
6184                 result = new NetworkUpdateResult(netId);
6185             }
6186             final int networkId = result.getNetworkId();
6187             mWifiConfigManager.userEnabledNetwork(networkId);
6188             if (!mWifiConfigManager.enableNetwork(networkId, true, callingUid, null)
6189                     || !mWifiConfigManager.updateLastConnectUid(networkId, callingUid)) {
6190                 logi("connect Allowing uid " + callingUid
6191                         + " with insufficient permissions to connect=" + networkId);
6192             } else if (mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
6193                 // Note user connect choice here, so that it will be considered in the
6194                 // next network selection.
6195                 mWifiConnectivityManager.setUserConnectChoice(networkId);
6196             }
6197             Message message =
6198                     obtainMessage(CMD_CONNECT_NETWORK, -1, callbackIdentifier, result);
6199             message.sendingUid = callingUid;
6200             sendMessage(message);
6201         });
6202     }
6203 
6204     /**
6205      * Trigger network save and provide status via the provided callback.
6206      */
6207     public void save(WifiConfiguration config, @Nullable IBinder binder,
6208             @Nullable IActionListener callback, int callbackIdentifier, int callingUid) {
6209         mWifiInjector.getWifiThreadRunner().post(() -> {
6210             if (callback != null && binder != null) {
6211                 mProcessingActionListeners.add(binder, callback, callbackIdentifier);
6212             }
6213             if (config == null) {
6214                 loge("saveNetwork with null configuration my state "
6215                         + getCurrentState().getName());
6216                 sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6217                 return;
6218             }
6219             NetworkUpdateResult result =
6220                     mWifiConfigManager.addOrUpdateNetwork(config, callingUid);
6221             if (!result.isSuccess()) {
6222                 loge("saveNetwork adding/updating config=" + config + " failed");
6223                 sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6224                 return;
6225             }
6226             if (!mWifiConfigManager.enableNetwork(
6227                     result.getNetworkId(), false, callingUid, null)) {
6228                 loge("saveNetwork enabling config=" + config + " failed");
6229                 sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6230                 return;
6231             }
6232             broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6233             Message message =
6234                     obtainMessage(CMD_SAVE_NETWORK, -1 , callbackIdentifier, result);
6235             message.sendingUid = callingUid;
6236             sendMessage(message);
6237         });
6238     }
6239 
6240     /**
6241      * Trigger network forget and provide status via the provided callback.
6242      */
forget(int netId, @Nullable IBinder binder, @Nullable IActionListener callback, int callbackIdentifier, int callingUid)6243     public void forget(int netId, @Nullable IBinder binder, @Nullable IActionListener callback,
6244             int callbackIdentifier, int callingUid) {
6245         mWifiInjector.getWifiThreadRunner().post(() -> {
6246             if (callback != null && binder != null) {
6247                 mProcessingActionListeners.add(binder, callback, callbackIdentifier);
6248             }
6249             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
6250             boolean success = mWifiConfigManager.removeNetwork(netId, callingUid, null);
6251             if (!success) {
6252                 loge("Failed to remove network");
6253                 sendActionListenerFailure(callbackIdentifier, WifiManager.ERROR);
6254             }
6255             sendActionListenerSuccess(callbackIdentifier);
6256             broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT, config);
6257         });
6258     }
6259 
6260     /**
6261      * Handle BSS transition request from Connected BSS.
6262      *
6263      * @param frameData Data retrieved from received BTM request frame.
6264      */
handleBssTransitionRequest(BtmFrameData frameData)6265     private void handleBssTransitionRequest(BtmFrameData frameData) {
6266         if (frameData == null) {
6267             return;
6268         }
6269 
6270         String bssid = mWifiInfo.getBSSID();
6271         String ssid = mWifiInfo.getSSID();
6272         if ((bssid == null) || (ssid == null) || WifiManager.UNKNOWN_SSID.equals(ssid)) {
6273             Log.e(TAG, "Failed to handle BSS transition: bssid: " + bssid + " ssid: " + ssid);
6274             return;
6275         }
6276 
6277         if ((frameData.mBssTmDataFlagsMask
6278                 & MboOceConstants.BTM_DATA_FLAG_MBO_CELL_DATA_CONNECTION_PREFERENCE_INCLUDED)
6279                 != 0) {
6280             mWifiMetrics.incrementMboCellularSwitchRequestCount();
6281         }
6282 
6283 
6284         if ((frameData.mBssTmDataFlagsMask
6285                 & MboOceConstants.BTM_DATA_FLAG_MBO_ASSOC_RETRY_DELAY_INCLUDED)
6286                 != 0) {
6287             long duration = frameData.mBlackListDurationMs;
6288             mWifiMetrics.incrementSteeringRequestCountIncludingMboAssocRetryDelay();
6289             if (duration == 0) {
6290                 /*
6291                  * When MBO assoc retry delay is set to zero(reserved as per spec),
6292                  * blacklist the BSS for sometime to avoid AP rejecting the re-connect request.
6293                  */
6294                 duration = MboOceConstants.DEFAULT_BLACKLIST_DURATION_MS;
6295             }
6296             // Blacklist the current BSS
6297             mBssidBlocklistMonitor.blockBssidForDurationMs(bssid, ssid, duration);
6298         }
6299 
6300         if (frameData.mStatus != MboOceConstants.BTM_RESPONSE_STATUS_ACCEPT) {
6301             // Trigger the network selection and re-connect to new network if available.
6302             mWifiMetrics.incrementForceScanCountDueToSteeringRequest();
6303             mWifiConnectivityManager.forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
6304         }
6305     }
6306 
6307     /**
6308      * @return true if this device supports FILS-SHA256
6309      */
isFilsSha256Supported()6310     private boolean isFilsSha256Supported() {
6311         return (mWifiNative.getSupportedFeatureSet(mInterfaceName) & WIFI_FEATURE_FILS_SHA256) != 0;
6312     }
6313 
6314     /**
6315      * @return true if this device supports FILS-SHA384
6316      */
isFilsSha384Supported()6317     private boolean isFilsSha384Supported() {
6318         return (mWifiNative.getSupportedFeatureSet(mInterfaceName) & WIFI_FEATURE_FILS_SHA384) != 0;
6319     }
6320 
6321     /**
6322      * Helper method to set the allowed key management schemes from
6323      * scan result.
6324      */
updateAllowedKeyManagementSchemesFromScanResult( WifiConfiguration config, ScanResult scanResult)6325     private void updateAllowedKeyManagementSchemesFromScanResult(
6326             WifiConfiguration config, ScanResult scanResult) {
6327         if (isFilsSha256Supported()
6328                 && ScanResultUtil.isScanResultForFilsSha256Network(scanResult)) {
6329             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA256);
6330         }
6331         if (isFilsSha384Supported()
6332                 && ScanResultUtil.isScanResultForFilsSha384Network(scanResult)) {
6333             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA384);
6334         }
6335     }
6336     /**
6337      * Update wifi configuration based on the matching scan result.
6338      *
6339      * @param config Wifi configuration object.
6340      * @param scanResult Scan result matching the network.
6341      */
updateWifiConfigFromMatchingScanResult(WifiConfiguration config, ScanResult scanResult)6342     private void updateWifiConfigFromMatchingScanResult(WifiConfiguration config,
6343             ScanResult scanResult) {
6344         updateAllowedKeyManagementSchemesFromScanResult(config, scanResult);
6345         if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256)
6346                 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA384)) {
6347             config.enterpriseConfig.setFieldValue(WifiEnterpriseConfig.EAP_ERP, "1");
6348         }
6349     }
6350 
6351     /**
6352      * Update the wifi configuration before sending connect to
6353      * supplicant/driver.
6354      *
6355      * @param config wifi configuration object.
6356      * @param bssid BSSID to assocaite with.
6357      */
updateWifiConfigOnStartConnection(WifiConfiguration config, String bssid)6358     void updateWifiConfigOnStartConnection(WifiConfiguration config, String bssid) {
6359         boolean canUpgradePskToSae = false;
6360         boolean isFrameworkWpa3SaeUpgradePossible = false;
6361         boolean isLegacyWpa2ApInScanResult = false;
6362 
6363         setTargetBssid(config, bssid);
6364 
6365         if (isWpa3SaeUpgradeEnabled() && config.allowedKeyManagement.get(
6366                 WifiConfiguration.KeyMgmt.WPA_PSK)) {
6367             isFrameworkWpa3SaeUpgradePossible = true;
6368         }
6369 
6370         if (isFrameworkWpa3SaeUpgradePossible && isWpa3SaeUpgradeOffloadEnabled()) {
6371             // Driver offload of upgrading legacy WPA/WPA2 connection to WPA3
6372             if (mVerboseLoggingEnabled) {
6373                 Log.d(TAG, "Driver upgrade legacy WPA/WPA2 connection to WPA3");
6374             }
6375             config.allowedAuthAlgorithms.clear();
6376             // Note: KeyMgmt.WPA2_PSK is already enabled, enable SAE as well
6377             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
6378             isFrameworkWpa3SaeUpgradePossible = false;
6379         }
6380         // Check if network selection selected a good WPA3 candidate AP for a WPA2
6381         // saved network.
6382         ScanResult scanResultCandidate = config.getNetworkSelectionStatus().getCandidate();
6383         if (isFrameworkWpa3SaeUpgradePossible && scanResultCandidate != null) {
6384             ScanResultMatchInfo scanResultMatchInfo = ScanResultMatchInfo
6385                     .fromScanResult(scanResultCandidate);
6386             if ((scanResultMatchInfo.networkType == WifiConfiguration.SECURITY_TYPE_SAE)) {
6387                 canUpgradePskToSae = true;
6388             } else {
6389                 // No SAE candidate
6390                 isFrameworkWpa3SaeUpgradePossible = false;
6391             }
6392         }
6393 
6394         /**
6395          *  Go through the matching scan results and update wifi config.
6396          */
6397         ScanResultMatchInfo key1 = ScanResultMatchInfo.fromWifiConfiguration(config);
6398         ScanRequestProxy scanRequestProxy = mWifiInjector.getScanRequestProxy();
6399         List<ScanResult> scanResults = scanRequestProxy.getScanResults();
6400         for (ScanResult scanResult : scanResults) {
6401             if (!config.SSID.equals(ScanResultUtil.createQuotedSSID(scanResult.SSID))) {
6402                 continue;
6403             }
6404             if (isFrameworkWpa3SaeUpgradePossible && !isLegacyWpa2ApInScanResult) {
6405                 if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
6406                         && !ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
6407                     // Found a legacy WPA2 AP in range. Do not upgrade the connection to WPA3 to
6408                     // allow seamless roaming within the ESS.
6409                     if (mVerboseLoggingEnabled) {
6410                         Log.d(TAG, "Found legacy WPA2 AP, do not upgrade to WPA3");
6411                     }
6412                     isLegacyWpa2ApInScanResult = true;
6413                     canUpgradePskToSae = false;
6414                 }
6415                 if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)
6416                         && scanResultCandidate == null) {
6417                     // When the user manually selected a network from the Wi-Fi picker, evaluate
6418                     // if to upgrade based on the scan results. The most typical use case during
6419                     // the WPA3 transition mode is to have a WPA2/WPA3 AP in transition mode. In
6420                     // this case, we would like to upgrade the connection.
6421                     canUpgradePskToSae = true;
6422                 }
6423             }
6424 
6425             ScanResultMatchInfo key2 = ScanResultMatchInfo.fromScanResult(scanResult);
6426             if (!key1.equals(key2)) {
6427                 continue;
6428             }
6429             updateWifiConfigFromMatchingScanResult(config, scanResult);
6430         }
6431 
6432         if (isFrameworkWpa3SaeUpgradePossible && canUpgradePskToSae
6433                 && !(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256)
6434                             || config.allowedKeyManagement.get(
6435                             WifiConfiguration.KeyMgmt.FILS_SHA384))) {
6436             // Upgrade legacy WPA/WPA2 connection to WPA3
6437             if (mVerboseLoggingEnabled) {
6438                 Log.d(TAG, "Upgrade legacy WPA/WPA2 connection to WPA3");
6439             }
6440             config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
6441         }
6442 
6443         if (isConnectedMacRandomizationEnabled()) {
6444             if (config.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_PERSISTENT) {
6445                 configureRandomizedMacAddress(config);
6446             } else {
6447                 setCurrentMacToFactoryMac(config);
6448             }
6449         }
6450 
6451         if (config.enterpriseConfig != null
6452                 && config.enterpriseConfig.isAuthenticationSimBased()
6453                 && mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(
6454                 mWifiCarrierInfoManager.getBestMatchSubscriptionId(config))
6455                 && TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) {
6456             String anonAtRealm = mWifiCarrierInfoManager
6457                     .getAnonymousIdentityWith3GppRealm(config);
6458             // Use anonymous@<realm> when pseudonym is not available
6459             config.enterpriseConfig.setAnonymousIdentity(anonAtRealm);
6460         }
6461     }
6462 
setConfigurationsPriorToIpClientProvisioning(WifiConfiguration config)6463     private void setConfigurationsPriorToIpClientProvisioning(WifiConfiguration config) {
6464         mIpClient.setHttpProxy(config.getHttpProxy());
6465         if (!TextUtils.isEmpty(mContext.getResources().getString(
6466                 R.string.config_wifi_tcp_buffers))) {
6467             mIpClient.setTcpBufferSizes(mContext.getResources().getString(
6468                     R.string.config_wifi_tcp_buffers));
6469         }
6470     }
6471 
startIpClient(WifiConfiguration config, boolean isFilsConnection)6472     private boolean startIpClient(WifiConfiguration config, boolean isFilsConnection) {
6473         if (mIpClient == null) {
6474             return false;
6475         }
6476 
6477         final boolean isUsingStaticIp =
6478                 (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
6479         final boolean isUsingMacRandomization =
6480                 config.macRandomizationSetting
6481                         == WifiConfiguration.RANDOMIZATION_PERSISTENT
6482                         && isConnectedMacRandomizationEnabled();
6483         if (mVerboseLoggingEnabled) {
6484             final String key = config.getKey();
6485             log("startIpClient netId=" + Integer.toString(mLastNetworkId)
6486                     + " " + key + " "
6487                     + " roam=" + mIsAutoRoaming
6488                     + " static=" + isUsingStaticIp
6489                     + " randomMac=" + isUsingMacRandomization
6490                     + " isFilsConnection=" + isFilsConnection);
6491         }
6492 
6493         final MacAddress currentBssid = getCurrentBssid();
6494         final String l2Key = mLastL2KeyAndGroupHint != null
6495                 ? mLastL2KeyAndGroupHint.first : null;
6496         final String groupHint = mLastL2KeyAndGroupHint != null
6497                 ? mLastL2KeyAndGroupHint.second : null;
6498         final Layer2Information layer2Info = new Layer2Information(l2Key, groupHint,
6499                 currentBssid);
6500 
6501         if (isFilsConnection) {
6502             stopIpClient();
6503             if (isUsingStaticIp) {
6504                 mWifiNative.flushAllHlp(mInterfaceName);
6505                 return false;
6506             }
6507             setConfigurationsPriorToIpClientProvisioning(config);
6508             final ProvisioningConfiguration.Builder prov =
6509                     new ProvisioningConfiguration.Builder()
6510                     .withPreDhcpAction()
6511                     .withPreconnection()
6512                     .withApfCapabilities(
6513                     mWifiNative.getApfCapabilities(mInterfaceName))
6514                     .withLayer2Information(layer2Info);
6515             if (isUsingMacRandomization) {
6516                 // Use EUI64 address generation for link-local IPv6 addresses.
6517                 prov.withRandomMacAddress();
6518             }
6519             mIpClient.startProvisioning(prov.build());
6520         } else {
6521             sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR);
6522             // We must clear the config BSSID, as the wifi chipset may decide to roam
6523             // from this point on and having the BSSID specified in the network block would
6524             // cause the roam to fail and the device to disconnect.
6525             clearTargetBssid("ObtainingIpAddress");
6526 
6527             // Stop IpClient in case we're switching from DHCP to static
6528             // configuration or vice versa.
6529             //
6530             // When we transition from static configuration to DHCP in
6531             // particular, we must tell ConnectivityService that we're
6532             // disconnected, because DHCP might take a long time during which
6533             // connectivity APIs such as getActiveNetworkInfo should not return
6534             // CONNECTED.
6535             stopDhcpSetup();
6536             setConfigurationsPriorToIpClientProvisioning(config);
6537             ScanDetailCache scanDetailCache =
6538                     mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
6539             ScanResult scanResult = null;
6540             if (mLastBssid != null) {
6541                 if (scanDetailCache != null) {
6542                     scanResult = scanDetailCache.getScanResult(mLastBssid);
6543                 }
6544 
6545                 // The cached scan result of connected network would be null at the first
6546                 // connection, try to check full scan result list again to look up matched
6547                 // scan result associated to the current SSID and BSSID.
6548                 if (scanResult == null) {
6549                     ScanRequestProxy scanRequestProxy = mWifiInjector.getScanRequestProxy();
6550                     List<ScanResult> scanResults = scanRequestProxy.getScanResults();
6551                     for (ScanResult result : scanResults) {
6552                         if (result.SSID.equals(WifiInfo.removeDoubleQuotes(config.SSID))
6553                                 && result.BSSID.equals(mLastBssid)) {
6554                             scanResult = result;
6555                             break;
6556                         }
6557                     }
6558                 }
6559             }
6560 
6561             final ProvisioningConfiguration.Builder prov;
6562             ProvisioningConfiguration.ScanResultInfo scanResultInfo = null;
6563             if (scanResult != null) {
6564                 final List<ScanResultInfo.InformationElement> ies =
6565                         new ArrayList<ScanResultInfo.InformationElement>();
6566                 for (ScanResult.InformationElement ie : scanResult.getInformationElements()) {
6567                     ScanResultInfo.InformationElement scanResultInfoIe =
6568                             new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes());
6569                     ies.add(scanResultInfoIe);
6570                 }
6571                 scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID,
6572                         scanResult.BSSID, ies);
6573             }
6574 
6575             if (!isUsingStaticIp) {
6576                 prov = new ProvisioningConfiguration.Builder()
6577                     .withPreDhcpAction()
6578                     .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
6579                     .withNetwork(getCurrentNetwork())
6580                     .withDisplayName(config.SSID)
6581                     .withScanResultInfo(scanResultInfo)
6582                     .withLayer2Information(layer2Info);
6583             } else {
6584                 StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
6585                 prov = new ProvisioningConfiguration.Builder()
6586                         .withStaticConfiguration(staticIpConfig)
6587                         .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
6588                         .withNetwork(getCurrentNetwork())
6589                         .withDisplayName(config.SSID)
6590                         .withLayer2Information(layer2Info);
6591             }
6592             if (isUsingMacRandomization) {
6593                 // Use EUI64 address generation for link-local IPv6 addresses.
6594                 prov.withRandomMacAddress();
6595             }
6596             mIpClient.startProvisioning(prov.build());
6597         }
6598 
6599         return true;
6600     }
6601 
6602 }
6603