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