• 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.WifiManager.WIFI_AP_STATE_DISABLED;
20 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
21 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
22 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
23 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
24 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
25 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
26 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
27 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
28 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
29 import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
30 import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
31 
32 import android.Manifest;
33 import android.app.ActivityManager;
34 import android.app.AppGlobals;
35 import android.app.PendingIntent;
36 import android.bluetooth.BluetoothAdapter;
37 import android.content.BroadcastReceiver;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.content.IntentFilter;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.IPackageManager;
43 import android.content.pm.PackageManager;
44 import android.database.ContentObserver;
45 import android.net.ConnectivityManager;
46 import android.net.DhcpResults;
47 import android.net.IpConfiguration;
48 import android.net.LinkProperties;
49 import android.net.Network;
50 import android.net.NetworkAgent;
51 import android.net.NetworkCapabilities;
52 import android.net.NetworkFactory;
53 import android.net.NetworkInfo;
54 import android.net.NetworkInfo.DetailedState;
55 import android.net.NetworkMisc;
56 import android.net.NetworkRequest;
57 import android.net.NetworkUtils;
58 import android.net.RouteInfo;
59 import android.net.StaticIpConfiguration;
60 import android.net.TrafficStats;
61 import android.net.dhcp.DhcpClient;
62 import android.net.ip.IpManager;
63 import android.net.wifi.IApInterface;
64 import android.net.wifi.IClientInterface;
65 import android.net.wifi.RssiPacketCountInfo;
66 import android.net.wifi.ScanResult;
67 import android.net.wifi.ScanSettings;
68 import android.net.wifi.SupplicantState;
69 import android.net.wifi.WifiChannel;
70 import android.net.wifi.WifiConfiguration;
71 import android.net.wifi.WifiConnectionStatistics;
72 import android.net.wifi.WifiEnterpriseConfig;
73 import android.net.wifi.WifiInfo;
74 import android.net.wifi.WifiLinkLayerStats;
75 import android.net.wifi.WifiManager;
76 import android.net.wifi.WifiScanner;
77 import android.net.wifi.WifiSsid;
78 import android.net.wifi.WpsInfo;
79 import android.net.wifi.WpsResult;
80 import android.net.wifi.WpsResult.Status;
81 import android.net.wifi.hotspot2.OsuProvider;
82 import android.net.wifi.hotspot2.PasspointConfiguration;
83 import android.net.wifi.p2p.IWifiP2pManager;
84 import android.os.BatteryStats;
85 import android.os.Binder;
86 import android.os.Build;
87 import android.os.Bundle;
88 import android.os.IBinder;
89 import android.os.INetworkManagementService;
90 import android.os.Looper;
91 import android.os.Message;
92 import android.os.Messenger;
93 import android.os.PowerManager;
94 import android.os.Process;
95 import android.os.RemoteException;
96 import android.os.UserHandle;
97 import android.os.UserManager;
98 import android.os.WorkSource;
99 import android.provider.Settings;
100 import android.telephony.PhoneStateListener;
101 import android.telephony.TelephonyManager;
102 import android.text.TextUtils;
103 import android.util.Log;
104 import android.util.Pair;
105 import android.util.SparseArray;
106 
107 import com.android.internal.R;
108 import com.android.internal.annotations.GuardedBy;
109 import com.android.internal.annotations.VisibleForTesting;
110 import com.android.internal.app.IBatteryStats;
111 import com.android.internal.util.AsyncChannel;
112 import com.android.internal.util.MessageUtils;
113 import com.android.internal.util.Protocol;
114 import com.android.internal.util.State;
115 import com.android.internal.util.StateMachine;
116 import com.android.server.connectivity.KeepalivePacketData;
117 import com.android.server.wifi.hotspot2.AnqpEvent;
118 import com.android.server.wifi.hotspot2.IconEvent;
119 import com.android.server.wifi.hotspot2.NetworkDetail;
120 import com.android.server.wifi.hotspot2.PasspointManager;
121 import com.android.server.wifi.hotspot2.Utils;
122 import com.android.server.wifi.hotspot2.WnmData;
123 import com.android.server.wifi.nano.WifiMetricsProto;
124 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
125 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
126 import com.android.server.wifi.util.NativeUtil;
127 import com.android.server.wifi.util.TelephonyUtil;
128 import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
129 import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
130 import com.android.server.wifi.util.WifiPermissionsUtil;
131 
132 import java.io.BufferedReader;
133 import java.io.FileDescriptor;
134 import java.io.FileNotFoundException;
135 import java.io.FileReader;
136 import java.io.IOException;
137 import java.io.PrintWriter;
138 import java.net.Inet4Address;
139 import java.net.InetAddress;
140 import java.util.ArrayList;
141 import java.util.Arrays;
142 import java.util.HashMap;
143 import java.util.HashSet;
144 import java.util.LinkedList;
145 import java.util.List;
146 import java.util.Map;
147 import java.util.Queue;
148 import java.util.Set;
149 import java.util.concurrent.atomic.AtomicBoolean;
150 import java.util.concurrent.atomic.AtomicInteger;
151 
152 /**
153  * TODO:
154  * Deprecate WIFI_STATE_UNKNOWN
155  */
156 
157 /**
158  * Track the state of Wifi connectivity. All event handling is done here,
159  * and all changes in connectivity state are initiated here.
160  *
161  * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
162  * In the current implementation, we support concurrent wifi p2p and wifi operation.
163  * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
164  * handles p2p operation.
165  *
166  * @hide
167  */
168 public class WifiStateMachine extends StateMachine implements WifiNative.WifiRssiEventHandler,
169         WifiMulticastLockManager.FilterController {
170 
171     private static final String NETWORKTYPE = "WIFI";
172     private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT";
173     @VisibleForTesting public static final short NUM_LOG_RECS_NORMAL = 100;
174     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE_LOW_MEMORY = 200;
175     @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE = 3000;
176     private static final String TAG = "WifiStateMachine";
177 
178     private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
179 
180     private static final String GOOGLE_OUI = "DA-A1-19";
181 
182     private static final String EXTRA_OSU_ICON_QUERY_BSSID = "BSSID";
183     private static final String EXTRA_OSU_ICON_QUERY_FILENAME = "FILENAME";
184 
185     private boolean mVerboseLoggingEnabled = false;
186 
187     /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
188      * the corresponding BSSID.
189      */
190     private boolean didBlackListBSSID = false;
191 
192     /**
193      * Log with error attribute
194      *
195      * @param s is string log
196      */
197     @Override
loge(String s)198     protected void loge(String s) {
199         Log.e(getName(), s);
200     }
201     @Override
logd(String s)202     protected void logd(String s) {
203         Log.d(getName(), s);
204     }
205     @Override
log(String s)206     protected void log(String s) {
207         Log.d(getName(), s);
208     }
209     private WifiMetrics mWifiMetrics;
210     private WifiInjector mWifiInjector;
211     private WifiMonitor mWifiMonitor;
212     private WifiNative mWifiNative;
213     private WifiPermissionsUtil mWifiPermissionsUtil;
214     private WifiConfigManager mWifiConfigManager;
215     private WifiConnectivityManager mWifiConnectivityManager;
216     private INetworkManagementService mNwService;
217     private IClientInterface mClientInterface;
218     private ConnectivityManager mCm;
219     private BaseWifiDiagnostics mWifiDiagnostics;
220     private WifiApConfigStore mWifiApConfigStore;
221     private final boolean mP2pSupported;
222     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
223     private boolean mTemporarilyDisconnectWifi = false;
224     private final String mPrimaryDeviceType;
225     private final Clock mClock;
226     private final PropertyService mPropertyService;
227     private final BuildProperties mBuildProperties;
228     private final WifiCountryCode mCountryCode;
229     // Object holding most recent wifi score report and bad Linkspeed count
230     private final WifiScoreReport mWifiScoreReport;
getWifiScoreReport()231     public WifiScoreReport getWifiScoreReport() {
232         return mWifiScoreReport;
233     }
234     private final PasspointManager mPasspointManager;
235 
236     /* Scan results handling */
237     private List<ScanDetail> mScanResults = new ArrayList<>();
238     private final Object mScanResultsLock = new Object();
239 
240     // For debug, number of known scan results that were found as part of last scan result event,
241     // as well the number of scans results returned by the supplicant with that message
242     private int mNumScanResultsKnown;
243     private int mNumScanResultsReturned;
244 
245     private boolean mScreenOn = false;
246 
247     private final String mInterfaceName;
248 
249     private int mLastSignalLevel = -1;
250     private String mLastBssid;
251     private int mLastNetworkId; // The network Id we successfully joined
252     private boolean mIsLinkDebouncing = false;
253     private final StateMachineDeathRecipient mDeathRecipient =
254             new StateMachineDeathRecipient(this, CMD_CLIENT_INTERFACE_BINDER_DEATH);
255     private final WifiNative.VendorHalDeathEventHandler mVendorHalDeathRecipient = () -> {
256         sendMessage(CMD_VENDOR_HAL_HWBINDER_DEATH);
257     };
258     private boolean mIpReachabilityDisconnectEnabled = true;
259 
260     @Override
onRssiThresholdBreached(byte curRssi)261     public void onRssiThresholdBreached(byte curRssi) {
262         if (mVerboseLoggingEnabled) {
263             Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi);
264         }
265         sendMessage(CMD_RSSI_THRESHOLD_BREACHED, curRssi);
266     }
267 
processRssiThreshold(byte curRssi, int reason)268     public void processRssiThreshold(byte curRssi, int reason) {
269         if (curRssi == Byte.MAX_VALUE || curRssi == Byte.MIN_VALUE) {
270             Log.wtf(TAG, "processRssiThreshold: Invalid rssi " + curRssi);
271             return;
272         }
273         for (int i = 0; i < mRssiRanges.length; i++) {
274             if (curRssi < mRssiRanges[i]) {
275                 // Assume sorted values(ascending order) for rssi,
276                 // bounded by high(127) and low(-128) at extremeties
277                 byte maxRssi = mRssiRanges[i];
278                 byte minRssi = mRssiRanges[i-1];
279                 // This value of hw has to be believed as this value is averaged and has breached
280                 // the rssi thresholds and raised event to host. This would be eggregious if this
281                 // value is invalid
282                 mWifiInfo.setRssi(curRssi);
283                 updateCapabilities();
284                 int ret = startRssiMonitoringOffload(maxRssi, minRssi);
285                 Log.d(TAG, "Re-program RSSI thresholds for " + smToString(reason) +
286                         ": [" + minRssi + ", " + maxRssi + "], curRssi=" + curRssi + " ret=" + ret);
287                 break;
288             }
289         }
290     }
291 
292     // Testing various network disconnect cases by sending lots of spurious
293     // disconnect to supplicant
294     private boolean testNetworkDisconnect = false;
295 
296     private boolean mEnableRssiPolling = false;
297     // Accessed via Binder thread ({get,set}PollRssiIntervalMsecs), and WifiStateMachine thread.
298     private volatile int mPollRssiIntervalMsecs = DEFAULT_POLL_RSSI_INTERVAL_MSECS;
299     private int mRssiPollToken = 0;
300     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
301     * In CONNECT_MODE, the STA can scan and connect to an access point
302     * In SCAN_ONLY_MODE, the STA can only scan for access points
303     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
304     */
305     private int mOperationalMode = CONNECT_MODE;
306     private boolean mIsScanOngoing = false;
307     private boolean mIsFullScanOngoing = false;
308 
309     private final Queue<Message> mBufferedScanMsg = new LinkedList<>();
310     private static final int UNKNOWN_SCAN_SOURCE = -1;
311     private static final int ADD_OR_UPDATE_SOURCE = -3;
312 
313     private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
314     private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
315     private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
316     private static final String SCAN_REQUEST_TIME = "scan_request_time";
317 
318     private boolean mBluetoothConnectionActive = false;
319 
320     private PowerManager.WakeLock mSuspendWakeLock;
321 
322     /**
323      * Interval in milliseconds between polling for RSSI
324      * and linkspeed information
325      */
326     private static final int DEFAULT_POLL_RSSI_INTERVAL_MSECS = 3000;
327 
328     /**
329      * Interval in milliseconds between receiving a disconnect event
330      * while connected to a good AP, and handling the disconnect proper
331      */
332     private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 4000;
333 
334     /**
335      * Delay between supplicant restarts upon failure to establish connection
336      */
337     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
338 
339     /**
340      * Number of times we attempt to restart supplicant
341      */
342     private static final int SUPPLICANT_RESTART_TRIES = 5;
343 
344     /**
345      * Value to set in wpa_supplicant "bssid" field when we don't want to restrict connection to
346      * a specific AP.
347      */
348     public static final String SUPPLICANT_BSSID_ANY = "any";
349 
350     private int mSupplicantRestartCount = 0;
351 
352     /**
353      * The link properties of the wifi interface.
354      * Do not modify this directly; use updateLinkProperties instead.
355      */
356     private LinkProperties mLinkProperties;
357 
358     /* Tracks sequence number on a periodic scan message */
359     private int mPeriodicScanToken = 0;
360 
361     // Wakelock held during wifi start/stop and driver load/unload
362     private PowerManager.WakeLock mWakeLock;
363 
364     private Context mContext;
365 
366     private final Object mDhcpResultsLock = new Object();
367     private DhcpResults mDhcpResults;
368 
369     // NOTE: Do not return to clients - see syncRequestConnectionInfo()
370     private final WifiInfo mWifiInfo;
371     private NetworkInfo mNetworkInfo;
372     private final NetworkCapabilities mDfltNetworkCapabilities;
373     private SupplicantStateTracker mSupplicantStateTracker;
374 
375     private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
376 
377     // Indicates that framework is attempting to roam, set true on CMD_START_ROAM, set false when
378     // wifi connects or fails to connect
379     private boolean mIsAutoRoaming = false;
380 
381     // Roaming failure count
382     private int mRoamFailCount = 0;
383 
384     // This is the BSSID we are trying to associate to, it can be set to SUPPLICANT_BSSID_ANY
385     // if we havent selected a BSSID for joining.
386     private String mTargetRoamBSSID = SUPPLICANT_BSSID_ANY;
387     // This one is used to track whta is the current target network ID. This is used for error
388     // handling during connection setup since many error message from supplicant does not report
389     // SSID Once connected, it will be set to invalid
390     private int mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
391     private long mLastDriverRoamAttempt = 0;
392     private WifiConfiguration targetWificonfiguration = null;
393 
getPollRssiIntervalMsecs()394     int getPollRssiIntervalMsecs() {
395         return mPollRssiIntervalMsecs;
396     }
397 
setPollRssiIntervalMsecs(int newPollIntervalMsecs)398     void setPollRssiIntervalMsecs(int newPollIntervalMsecs) {
399         mPollRssiIntervalMsecs = newPollIntervalMsecs;
400     }
401 
402     /**
403      * Method to clear {@link #mTargetRoamBSSID} and reset the the current connected network's
404      * bssid in wpa_supplicant after a roam/connect attempt.
405      */
clearTargetBssid(String dbg)406     public boolean clearTargetBssid(String dbg) {
407         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
408         if (config == null) {
409             return false;
410         }
411         String bssid = SUPPLICANT_BSSID_ANY;
412         if (config.BSSID != null) {
413             bssid = config.BSSID;
414             if (mVerboseLoggingEnabled) {
415                 Log.d(TAG, "force BSSID to " + bssid + "due to config");
416             }
417         }
418         if (mVerboseLoggingEnabled) {
419             logd(dbg + " clearTargetBssid " + bssid + " key=" + config.configKey());
420         }
421         mTargetRoamBSSID = bssid;
422         return mWifiNative.setConfiguredNetworkBSSID(bssid);
423     }
424 
425     /**
426      * Set Config's default BSSID (for association purpose) and {@link #mTargetRoamBSSID}
427      * @param config config need set BSSID
428      * @param bssid  default BSSID to assocaite with when connect to this network
429      * @return false -- does not change the current default BSSID of the configure
430      *         true -- change the  current default BSSID of the configur
431      */
setTargetBssid(WifiConfiguration config, String bssid)432     private boolean setTargetBssid(WifiConfiguration config, String bssid) {
433         if (config == null || bssid == null) {
434             return false;
435         }
436         if (config.BSSID != null) {
437             bssid = config.BSSID;
438             if (mVerboseLoggingEnabled) {
439                 Log.d(TAG, "force BSSID to " + bssid + "due to config");
440             }
441         }
442         if (mVerboseLoggingEnabled) {
443             Log.d(TAG, "setTargetBssid set to " + bssid + " key=" + config.configKey());
444         }
445         mTargetRoamBSSID = bssid;
446         config.getNetworkSelectionStatus().setNetworkSelectionBSSID(bssid);
447         return true;
448     }
449 
450     private final IpManager mIpManager;
451 
452     // Channel for sending replies.
453     private AsyncChannel mReplyChannel = new AsyncChannel();
454 
455     // Used to initiate a connection with WifiP2pService
456     private AsyncChannel mWifiP2pChannel;
457 
458     private WifiScanner mWifiScanner;
459 
460     @GuardedBy("mWifiReqCountLock")
461     private int mConnectionReqCount = 0;
462     private WifiNetworkFactory mNetworkFactory;
463     @GuardedBy("mWifiReqCountLock")
464     private int mUntrustedReqCount = 0;
465     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
466     private WifiNetworkAgent mNetworkAgent;
467     private final Object mWifiReqCountLock = new Object();
468 
469     private byte[] mRssiRanges;
470 
471     // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
472     // We should really persist that into the networkHistory.txt file, and read it back when
473     // WifiStateMachine starts up
474     private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics();
475 
476     // Used to filter out requests we couldn't possibly satisfy.
477     private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
478 
479     // Provide packet filter capabilities to ConnectivityService.
480     private final NetworkMisc mNetworkMisc = new NetworkMisc();
481 
482     /* The base for wifi message types */
483     static final int BASE = Protocol.BASE_WIFI;
484     /* Start the supplicant */
485     static final int CMD_START_SUPPLICANT                               = BASE + 11;
486     /* Stop the supplicant */
487     static final int CMD_STOP_SUPPLICANT                                = BASE + 12;
488     /* Indicates Static IP succeeded */
489     static final int CMD_STATIC_IP_SUCCESS                              = BASE + 15;
490     /* Indicates Static IP failed */
491     static final int CMD_STATIC_IP_FAILURE                              = BASE + 16;
492     /* A delayed message sent to start driver when it fail to come up */
493     static final int CMD_DRIVER_START_TIMED_OUT                         = BASE + 19;
494 
495     /* Start the soft access point */
496     static final int CMD_START_AP                                       = BASE + 21;
497     /* Indicates soft ap start failed */
498     static final int CMD_START_AP_FAILURE                               = BASE + 22;
499     /* Stop the soft access point */
500     static final int CMD_STOP_AP                                        = BASE + 23;
501     /* Soft access point teardown is completed. */
502     static final int CMD_AP_STOPPED                                     = BASE + 24;
503 
504     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE                 = BASE + 31;
505 
506     /* Supplicant commands */
507     /* Add/update a network configuration */
508     static final int CMD_ADD_OR_UPDATE_NETWORK                          = BASE + 52;
509     /* Delete a network */
510     static final int CMD_REMOVE_NETWORK                                 = BASE + 53;
511     /* Enable a network. The device will attempt a connection to the given network. */
512     static final int CMD_ENABLE_NETWORK                                 = BASE + 54;
513     /* Save configuration */
514     static final int CMD_SAVE_CONFIG                                    = BASE + 58;
515     /* Get configured networks */
516     static final int CMD_GET_CONFIGURED_NETWORKS                        = BASE + 59;
517     /* Get adaptors */
518     static final int CMD_GET_SUPPORTED_FEATURES                         = BASE + 61;
519     /* Get configured networks with real preSharedKey */
520     static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS             = BASE + 62;
521     /* Get Link Layer Stats thru HAL */
522     static final int CMD_GET_LINK_LAYER_STATS                           = BASE + 63;
523     /* Supplicant commands after driver start*/
524     /* Initiate a scan */
525     static final int CMD_START_SCAN                                     = BASE + 71;
526     /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
527     static final int CMD_SET_OPERATIONAL_MODE                           = BASE + 72;
528     /* Disconnect from a network */
529     static final int CMD_DISCONNECT                                     = BASE + 73;
530     /* Reconnect to a network */
531     static final int CMD_RECONNECT                                      = BASE + 74;
532     /* Reassociate to a network */
533     static final int CMD_REASSOCIATE                                    = BASE + 75;
534     /* Get Connection Statistis */
535     static final int CMD_GET_CONNECTION_STATISTICS                      = BASE + 76;
536 
537     /* Controls suspend mode optimizations
538      *
539      * When high perf mode is enabled, suspend mode optimizations are disabled
540      *
541      * When high perf mode is disabled, suspend mode optimizations are enabled
542      *
543      * Suspend mode optimizations include:
544      * - packet filtering
545      * - turn off roaming
546      * - DTIM wake up settings
547      */
548     static final int CMD_SET_HIGH_PERF_MODE                             = BASE + 77;
549     /* Enables RSSI poll */
550     static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
551     /* RSSI poll */
552     static final int CMD_RSSI_POLL                                      = BASE + 83;
553     /* Enable suspend mode optimizations in the driver */
554     static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
555     /* Delayed NETWORK_DISCONNECT */
556     static final int CMD_DELAYED_NETWORK_DISCONNECT                     = BASE + 87;
557     /* When there are no saved networks, we do a periodic scan to notify user of
558      * an open network */
559     static final int CMD_NO_NETWORKS_PERIODIC_SCAN                      = BASE + 88;
560     /* Test network Disconnection NETWORK_DISCONNECT */
561     static final int CMD_TEST_NETWORK_DISCONNECT                        = BASE + 89;
562 
563     private int testNetworkDisconnectCounter = 0;
564 
565     /* Enable TDLS on a specific MAC address */
566     static final int CMD_ENABLE_TDLS                                    = BASE + 92;
567 
568     /**
569      * Watchdog for protecting against b/16823537
570      * Leave time for 4-way handshake to succeed
571      */
572     static final int ROAM_GUARD_TIMER_MSEC = 15000;
573 
574     int roamWatchdogCount = 0;
575     /* Roam state watchdog */
576     static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
577     /* Screen change intent handling */
578     static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
579 
580     /* Disconnecting state watchdog */
581     static final int CMD_DISCONNECTING_WATCHDOG_TIMER                   = BASE + 96;
582 
583     /* Remove a packages associated configrations */
584     static final int CMD_REMOVE_APP_CONFIGURATIONS                      = BASE + 97;
585 
586     /* Disable an ephemeral network */
587     static final int CMD_DISABLE_EPHEMERAL_NETWORK                      = BASE + 98;
588 
589     /* Get matching network */
590     static final int CMD_GET_MATCHING_CONFIG                            = BASE + 99;
591 
592     /* alert from firmware */
593     static final int CMD_FIRMWARE_ALERT                                 = BASE + 100;
594 
595     /* SIM is removed; reset any cached data for it */
596     static final int CMD_RESET_SIM_NETWORKS                             = BASE + 101;
597 
598     /* OSU APIs */
599     static final int CMD_QUERY_OSU_ICON                                 = BASE + 104;
600 
601     /* try to match a provider with current network */
602     static final int CMD_MATCH_PROVIDER_NETWORK                         = BASE + 105;
603 
604     // Add or update a Passpoint configuration.
605     static final int CMD_ADD_OR_UPDATE_PASSPOINT_CONFIG                 = BASE + 106;
606 
607     // Remove a Passpoint configuration.
608     static final int CMD_REMOVE_PASSPOINT_CONFIG                        = BASE + 107;
609 
610     // Get the list of installed Passpoint configurations.
611     static final int CMD_GET_PASSPOINT_CONFIGS                          = BASE + 108;
612 
613     // Get the list of OSU providers associated with a Passpoint network.
614     static final int CMD_GET_MATCHING_OSU_PROVIDERS                     = BASE + 109;
615 
616     /* Commands from/to the SupplicantStateTracker */
617     /* Reset the supplicant state tracker */
618     static final int CMD_RESET_SUPPLICANT_STATE                         = BASE + 111;
619 
620     int disconnectingWatchdogCount = 0;
621     static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
622 
623     /* Disable p2p watchdog */
624     static final int CMD_DISABLE_P2P_WATCHDOG_TIMER                   = BASE + 112;
625 
626     int mDisableP2pWatchdogCount = 0;
627     static final int DISABLE_P2P_GUARD_TIMER_MSEC = 2000;
628 
629     /* P2p commands */
630     /* We are ok with no response here since we wont do much with it anyway */
631     public static final int CMD_ENABLE_P2P                              = BASE + 131;
632     /* In order to shut down supplicant cleanly, we wait till p2p has
633      * been disabled */
634     public static final int CMD_DISABLE_P2P_REQ                         = BASE + 132;
635     public static final int CMD_DISABLE_P2P_RSP                         = BASE + 133;
636 
637     /**
638      * Indicates the end of boot process, should be used to trigger load from config store,
639      * initiate connection attempt, etc.
640      * */
641     static final int CMD_BOOT_COMPLETED                                 = BASE + 134;
642     /**
643      * Initialize the WifiStateMachine. This is currently used to initialize the
644      * {@link HalDeviceManager} module.
645      */
646     static final int CMD_INITIALIZE                                     = BASE + 135;
647 
648     /* We now have a valid IP configuration. */
649     static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
650     /* We no longer have a valid IP configuration. */
651     static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
652     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
653     static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
654 
655     /* Supplicant is trying to associate to a given BSSID */
656     static final int CMD_TARGET_BSSID                                   = BASE + 141;
657 
658     /* Reload all networks and reconnect */
659     static final int CMD_RELOAD_TLS_AND_RECONNECT                       = BASE + 142;
660 
661     static final int CMD_START_CONNECT                                  = BASE + 143;
662 
663     private static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
664     private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
665     private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
666 
667     static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
668 
669     static final int CMD_START_ROAM                                     = BASE + 145;
670 
671     static final int CMD_ASSOCIATED_BSSID                               = BASE + 147;
672 
673     static final int CMD_NETWORK_STATUS                                 = BASE + 148;
674 
675     /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
676     static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
677 
678     /* Remove a packages associated configrations */
679     static final int CMD_REMOVE_USER_CONFIGURATIONS                     = BASE + 152;
680 
681     static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
682 
683     /* used to offload sending IP packet */
684     static final int CMD_START_IP_PACKET_OFFLOAD                        = BASE + 160;
685 
686     /* used to stop offload sending IP packet */
687     static final int CMD_STOP_IP_PACKET_OFFLOAD                         = BASE + 161;
688 
689     /* used to start rssi monitoring in hw */
690     static final int CMD_START_RSSI_MONITORING_OFFLOAD                  = BASE + 162;
691 
692     /* used to stop rssi moniroting in hw */
693     static final int CMD_STOP_RSSI_MONITORING_OFFLOAD                   = BASE + 163;
694 
695     /* used to indicated RSSI threshold breach in hw */
696     static final int CMD_RSSI_THRESHOLD_BREACHED                        = BASE + 164;
697 
698     /* Enable/Disable WifiConnectivityManager */
699     static final int CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER               = BASE + 166;
700 
701     /* Enable/Disable AutoJoin when associated */
702     static final int CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED                = BASE + 167;
703 
704     /**
705      * Used to handle messages bounced between WifiStateMachine and IpManager.
706      */
707     static final int CMD_IPV4_PROVISIONING_SUCCESS                      = BASE + 200;
708     static final int CMD_IPV4_PROVISIONING_FAILURE                      = BASE + 201;
709 
710     /* Push a new APF program to the HAL */
711     static final int CMD_INSTALL_PACKET_FILTER                          = BASE + 202;
712 
713     /* Enable/disable fallback packet filtering */
714     static final int CMD_SET_FALLBACK_PACKET_FILTERING                  = BASE + 203;
715 
716     /* Enable/disable Neighbor Discovery offload functionality. */
717     static final int CMD_CONFIG_ND_OFFLOAD                              = BASE + 204;
718 
719     /* used to indicate that the foreground user was switched */
720     static final int CMD_USER_SWITCH                                    = BASE + 205;
721 
722     /* used to indicate that the foreground user was switched */
723     static final int CMD_USER_UNLOCK                                    = BASE + 206;
724 
725     /* used to indicate that the foreground user was switched */
726     static final int CMD_USER_STOP                                      = BASE + 207;
727 
728     /* Signals that IClientInterface instance underpinning our state is dead. */
729     private static final int CMD_CLIENT_INTERFACE_BINDER_DEATH          = BASE + 250;
730 
731     /* Signals that the Vendor HAL instance underpinning our state is dead. */
732     private static final int CMD_VENDOR_HAL_HWBINDER_DEATH              = BASE + 251;
733 
734     /* Indicates that diagnostics should time out a connection start event. */
735     private static final int CMD_DIAGS_CONNECT_TIMEOUT                  = BASE + 252;
736 
737     /* Used to set the tx power limit for SAR during the start of a phone call. */
738     private static final int CMD_SELECT_TX_POWER_SCENARIO               = BASE + 253;
739 
740     // For message logging.
741     private static final Class[] sMessageClasses = {
742             AsyncChannel.class, WifiStateMachine.class, DhcpClient.class };
743     private static final SparseArray<String> sSmToString =
744             MessageUtils.findMessageNames(sMessageClasses);
745 
746 
747     /* Wifi state machine modes of operation */
748     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
749     public static final int CONNECT_MODE = 1;
750     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
751     public static final int SCAN_ONLY_MODE = 2;
752     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
753     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
754     /* DISABLED_MODE - Don't connect, don't scan, don't be an AP */
755     public static final int DISABLED_MODE = 4;
756 
757     private static final int SUCCESS = 1;
758     private static final int FAILURE = -1;
759 
760     /* Tracks if suspend optimizations need to be disabled by DHCP,
761      * screen or due to high perf mode.
762      * When any of them needs to disable it, we keep the suspend optimizations
763      * disabled
764      */
765     private int mSuspendOptNeedsDisabled = 0;
766 
767     private static final int SUSPEND_DUE_TO_DHCP = 1;
768     private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
769     private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
770 
771     /**
772      * Time window in milliseconds for which we send
773      * {@link NetworkAgent#explicitlySelected(boolean)}
774      * after connecting to the network which the user last selected.
775      */
776     @VisibleForTesting
777     public static final int LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS = 30 * 1000;
778 
779     /* Tracks if user has enabled suspend optimizations through settings */
780     private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
781 
782     /**
783      * Scan period for the NO_NETWORKS_PERIIDOC_SCAN_FEATURE
784      */
785     private final int mNoNetworksPeriodicScan;
786 
787     /**
788      * Supplicant scan interval in milliseconds.
789      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
790      * from the default config if the setting is not set
791      */
792     private long mSupplicantScanIntervalMs;
793 
794     private boolean mEnableAutoJoinWhenAssociated;
795     private int mAlwaysEnableScansWhileAssociated;
796     private final int mThresholdQualifiedRssi24;
797     private final int mThresholdQualifiedRssi5;
798     private final int mThresholdSaturatedRssi24;
799     private final int mThresholdSaturatedRssi5;
800     private final int mThresholdMinimumRssi5;
801     private final int mThresholdMinimumRssi24;
802     private final boolean mEnableLinkDebouncing;
803     private final boolean mEnableChipWakeUpWhenAssociated;
804     private final boolean mEnableRssiPollWhenAssociated;
805     private final boolean mEnableVoiceCallSarTxPowerLimit;
806 
807     int mRunningBeaconCount = 0;
808 
809     /* Default parent state */
810     private State mDefaultState = new DefaultState();
811     /* Temporary initial state */
812     private State mInitialState = new InitialState();
813     /* Driver loaded, waiting for supplicant to start */
814     private State mSupplicantStartingState = new SupplicantStartingState();
815     /* Driver loaded and supplicant ready */
816     private State mSupplicantStartedState = new SupplicantStartedState();
817     /* Waiting for supplicant to stop and monitor to exit */
818     private State mSupplicantStoppingState = new SupplicantStoppingState();
819     /* Wait until p2p is disabled
820      * This is a special state which is entered right after we exit out of DriverStartedState
821      * before transitioning to another state.
822      */
823     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
824     /* Scan for networks, no connection will be established */
825     private State mScanModeState = new ScanModeState();
826     /* Connecting to an access point */
827     private State mConnectModeState = new ConnectModeState();
828     /* Connected at 802.11 (L2) level */
829     private State mL2ConnectedState = new L2ConnectedState();
830     /* fetching IP after connection to access point (assoc+auth complete) */
831     private State mObtainingIpState = new ObtainingIpState();
832     /* Connected with IP addr */
833     private State mConnectedState = new ConnectedState();
834     /* Roaming */
835     private State mRoamingState = new RoamingState();
836     /* disconnect issued, waiting for network disconnect confirmation */
837     private State mDisconnectingState = new DisconnectingState();
838     /* Network is not connected, supplicant assoc+auth is not complete */
839     private State mDisconnectedState = new DisconnectedState();
840     /* Waiting for WPS to be completed*/
841     private State mWpsRunningState = new WpsRunningState();
842     /* Soft ap state */
843     private State mSoftApState = new SoftApState();
844 
845     /**
846      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
847      * {@link WifiManager#WIFI_STATE_DISABLING},
848      * {@link WifiManager#WIFI_STATE_ENABLED},
849      * {@link WifiManager#WIFI_STATE_ENABLING},
850      * {@link WifiManager#WIFI_STATE_UNKNOWN}
851      */
852     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
853 
854     /**
855      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
856      * {@link WifiManager#WIFI_AP_STATE_DISABLING},
857      * {@link WifiManager#WIFI_AP_STATE_ENABLED},
858      * {@link WifiManager#WIFI_AP_STATE_ENABLING},
859      * {@link WifiManager#WIFI_AP_STATE_FAILED}
860      */
861     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
862 
863     /**
864      * Work source to use to blame usage on the WiFi service
865      */
866     public static final WorkSource WIFI_WORK_SOURCE = new WorkSource(Process.WIFI_UID);
867 
868     /**
869      * Keep track of whether WIFI is running.
870      */
871     private boolean mIsRunning = false;
872 
873     /**
874      * Keep track of whether we last told the battery stats we had started.
875      */
876     private boolean mReportedRunning = false;
877 
878     /**
879      * Most recently set source of starting WIFI.
880      */
881     private final WorkSource mRunningWifiUids = new WorkSource();
882 
883     /**
884      * The last reported UIDs that were responsible for starting WIFI.
885      */
886     private final WorkSource mLastRunningWifiUids = new WorkSource();
887 
888     private TelephonyManager mTelephonyManager;
getTelephonyManager()889     private TelephonyManager getTelephonyManager() {
890         if (mTelephonyManager == null) {
891             mTelephonyManager = mWifiInjector.makeTelephonyManager();
892         }
893         return mTelephonyManager;
894     }
895     private final WifiPhoneStateListener mPhoneStateListener;
896 
897     private final IBatteryStats mBatteryStats;
898 
899     private final String mTcpBufferSizes;
900 
901     // Used for debug and stats gathering
902     private static int sScanAlarmIntentCount = 0;
903 
904     private FrameworkFacade mFacade;
905     private WifiStateTracker mWifiStateTracker;
906     private final BackupManagerProxy mBackupManagerProxy;
907     private final WrongPasswordNotifier mWrongPasswordNotifier;
908 
WifiStateMachine(Context context, FrameworkFacade facade, Looper looper, UserManager userManager, WifiInjector wifiInjector, BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode, WifiNative wifiNative, WrongPasswordNotifier wrongPasswordNotifier)909     public WifiStateMachine(Context context, FrameworkFacade facade, Looper looper,
910                             UserManager userManager, WifiInjector wifiInjector,
911                             BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode,
912                             WifiNative wifiNative,
913                             WrongPasswordNotifier wrongPasswordNotifier) {
914         super("WifiStateMachine", looper);
915         mWifiInjector = wifiInjector;
916         mWifiMetrics = mWifiInjector.getWifiMetrics();
917         mClock = wifiInjector.getClock();
918         mPropertyService = wifiInjector.getPropertyService();
919         mBuildProperties = wifiInjector.getBuildProperties();
920         mContext = context;
921         mFacade = facade;
922         mWifiNative = wifiNative;
923         mBackupManagerProxy = backupManagerProxy;
924         mWrongPasswordNotifier = wrongPasswordNotifier;
925 
926         // TODO refactor WifiNative use of context out into it's own class
927         mInterfaceName = mWifiNative.getInterfaceName();
928         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
929         mBatteryStats = IBatteryStats.Stub.asInterface(mFacade.getService(
930                 BatteryStats.SERVICE_NAME));
931         mWifiStateTracker = wifiInjector.getWifiStateTracker();
932         IBinder b = mFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
933         mNwService = INetworkManagementService.Stub.asInterface(b);
934 
935         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
936                 PackageManager.FEATURE_WIFI_DIRECT);
937 
938         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
939         mWifiConfigManager = mWifiInjector.getWifiConfigManager();
940         mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
941 
942         mPasspointManager = mWifiInjector.getPasspointManager();
943 
944         mWifiMonitor = mWifiInjector.getWifiMonitor();
945         mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative);
946 
947         mWifiInfo = new WifiInfo();
948         mSupplicantStateTracker =
949                 mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
950 
951         mLinkProperties = new LinkProperties();
952         mPhoneStateListener = new WifiPhoneStateListener(looper);
953 
954         mNetworkInfo.setIsAvailable(false);
955         mLastBssid = null;
956         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
957         mLastSignalLevel = -1;
958 
959         mIpManager = mFacade.makeIpManager(mContext, mInterfaceName, new IpManagerCallback());
960         mIpManager.setMulticastFilter(true);
961 
962         mNoNetworksPeriodicScan = mContext.getResources().getInteger(
963                 R.integer.config_wifi_no_network_periodic_scan_interval);
964 
965         // TODO: remove these settings from the config file since we no longer obey them
966         // mContext.getResources().getInteger(R.integer.config_wifi_framework_scan_interval);
967         // mContext.getResources().getBoolean(R.bool.config_wifi_background_scan_support);
968 
969         mPrimaryDeviceType = mContext.getResources().getString(
970                 R.string.config_wifi_p2p_device_type);
971 
972         mCountryCode = countryCode;
973 
974         mWifiScoreReport = new WifiScoreReport(mContext, mWifiConfigManager, mClock);
975 
976         mUserWantsSuspendOpt.set(mFacade.getIntegerSetting(mContext,
977                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
978 
979         mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
980         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
981         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
982         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
983         mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
984         mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
985         // TODO - needs to be a bit more dynamic
986         mDfltNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
987 
988         IntentFilter filter = new IntentFilter();
989         filter.addAction(Intent.ACTION_SCREEN_ON);
990         filter.addAction(Intent.ACTION_SCREEN_OFF);
991         mContext.registerReceiver(
992                 new BroadcastReceiver() {
993                     @Override
994                     public void onReceive(Context context, Intent intent) {
995                         String action = intent.getAction();
996 
997                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
998                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
999                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1000                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
1001                         }
1002                     }
1003                 }, filter);
1004 
1005         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
1006                         Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
1007                 new ContentObserver(getHandler()) {
1008                     @Override
1009                     public void onChange(boolean selfChange) {
1010                         mUserWantsSuspendOpt.set(mFacade.getIntegerSetting(mContext,
1011                                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
1012                     }
1013                 });
1014 
1015         mContext.registerReceiver(
1016                 new BroadcastReceiver() {
1017                     @Override
1018                     public void onReceive(Context context, Intent intent) {
1019                         sendMessage(CMD_BOOT_COMPLETED);
1020                     }
1021                 },
1022                 new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
1023 
1024         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1025         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
1026 
1027         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
1028         mSuspendWakeLock.setReferenceCounted(false);
1029 
1030         mTcpBufferSizes = mContext.getResources().getString(
1031                 com.android.internal.R.string.config_wifi_tcp_buffers);
1032 
1033         // Load Device configs
1034         mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
1035                 R.bool.config_wifi_framework_enable_associated_network_selection);
1036         mThresholdQualifiedRssi24 = context.getResources().getInteger(
1037                 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
1038         mThresholdQualifiedRssi5 = context.getResources().getInteger(
1039                 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
1040         mThresholdSaturatedRssi24 = context.getResources().getInteger(
1041                 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
1042         mThresholdSaturatedRssi5 = context.getResources().getInteger(
1043                 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
1044         mThresholdMinimumRssi5 = context.getResources().getInteger(
1045                 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
1046         mThresholdMinimumRssi24 = context.getResources().getInteger(
1047                 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
1048         mEnableLinkDebouncing = mContext.getResources().getBoolean(
1049                 R.bool.config_wifi_enable_disconnection_debounce);
1050         mEnableVoiceCallSarTxPowerLimit = mContext.getResources().getBoolean(
1051                 R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit);
1052         mEnableChipWakeUpWhenAssociated = true;
1053         mEnableRssiPollWhenAssociated = true;
1054 
1055         // CHECKSTYLE:OFF IndentationCheck
1056         addState(mDefaultState);
1057             addState(mInitialState, mDefaultState);
1058             addState(mSupplicantStartingState, mDefaultState);
1059             addState(mSupplicantStartedState, mDefaultState);
1060                     addState(mScanModeState, mSupplicantStartedState);
1061                     addState(mConnectModeState, mSupplicantStartedState);
1062                         addState(mL2ConnectedState, mConnectModeState);
1063                             addState(mObtainingIpState, mL2ConnectedState);
1064                             addState(mConnectedState, mL2ConnectedState);
1065                             addState(mRoamingState, mL2ConnectedState);
1066                         addState(mDisconnectingState, mConnectModeState);
1067                         addState(mDisconnectedState, mConnectModeState);
1068                         addState(mWpsRunningState, mConnectModeState);
1069                 addState(mWaitForP2pDisableState, mSupplicantStartedState);
1070             addState(mSupplicantStoppingState, mDefaultState);
1071             addState(mSoftApState, mDefaultState);
1072         // CHECKSTYLE:ON IndentationCheck
1073 
1074         setInitialState(mInitialState);
1075 
1076         setLogRecSize(NUM_LOG_RECS_NORMAL);
1077         setLogOnlyTransitions(false);
1078 
1079         //start the state machine
1080         start();
1081 
1082         // Learn the initial state of whether the screen is on.
1083         // We update this field when we receive broadcasts from the system.
1084         handleScreenStateChanged(powerManager.isInteractive());
1085 
1086         mWifiMonitor.registerHandler(mInterfaceName, CMD_TARGET_BSSID, getHandler());
1087         mWifiMonitor.registerHandler(mInterfaceName, CMD_ASSOCIATED_BSSID, getHandler());
1088         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ANQP_DONE_EVENT, getHandler());
1089         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
1090                 getHandler());
1091         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
1092                 getHandler());
1093         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_DONE_EVENT, getHandler());
1094         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_START_EVENT,
1095                 getHandler());
1096         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.HS20_REMEDIATION_EVENT,
1097                 getHandler());
1098         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
1099                 getHandler());
1100         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
1101                 getHandler());
1102         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
1103                 getHandler());
1104         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_FAILED_EVENT, getHandler());
1105         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_RESULTS_EVENT, getHandler());
1106         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
1107         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_DISCONNECTION_EVENT,
1108                 getHandler());
1109         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
1110                 getHandler());
1111         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_IDENTITY, getHandler());
1112         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_SIM_AUTH, getHandler());
1113         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_FAIL_EVENT, getHandler());
1114         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_OVERLAP_EVENT, getHandler());
1115         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_SUCCESS_EVENT, getHandler());
1116         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_TIMEOUT_EVENT, getHandler());
1117 
1118         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
1119                 mWifiMetrics.getHandler());
1120         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
1121                 mWifiMetrics.getHandler());
1122         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
1123                 mWifiMetrics.getHandler());
1124         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
1125                 mWifiMetrics.getHandler());
1126         mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
1127                 mWifiMetrics.getHandler());
1128         mWifiMonitor.registerHandler(mInterfaceName, CMD_ASSOCIATED_BSSID,
1129                 mWifiMetrics.getHandler());
1130         mWifiMonitor.registerHandler(mInterfaceName, CMD_TARGET_BSSID,
1131                 mWifiMetrics.getHandler());
1132 
1133         final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
1134         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1135         intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
1136         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1137     }
1138 
1139     class IpManagerCallback extends IpManager.Callback {
1140         @Override
onPreDhcpAction()1141         public void onPreDhcpAction() {
1142             sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
1143         }
1144 
1145         @Override
onPostDhcpAction()1146         public void onPostDhcpAction() {
1147             sendMessage(DhcpClient.CMD_POST_DHCP_ACTION);
1148         }
1149 
1150         @Override
onNewDhcpResults(DhcpResults dhcpResults)1151         public void onNewDhcpResults(DhcpResults dhcpResults) {
1152             if (dhcpResults != null) {
1153                 sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, dhcpResults);
1154             } else {
1155                 sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
1156                 mWifiInjector.getWifiLastResortWatchdog().noteConnectionFailureAndTriggerIfNeeded(
1157                         getTargetSsid(), mTargetRoamBSSID,
1158                         WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1159             }
1160         }
1161 
1162         @Override
onProvisioningSuccess(LinkProperties newLp)1163         public void onProvisioningSuccess(LinkProperties newLp) {
1164             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL);
1165             sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1166             sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
1167         }
1168 
1169         @Override
onProvisioningFailure(LinkProperties newLp)1170         public void onProvisioningFailure(LinkProperties newLp) {
1171             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST);
1172             sendMessage(CMD_IP_CONFIGURATION_LOST);
1173         }
1174 
1175         @Override
onLinkPropertiesChange(LinkProperties newLp)1176         public void onLinkPropertiesChange(LinkProperties newLp) {
1177             sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1178         }
1179 
1180         @Override
onReachabilityLost(String logMsg)1181         public void onReachabilityLost(String logMsg) {
1182             mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_REACHABILITY_LOST);
1183             sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
1184         }
1185 
1186         @Override
installPacketFilter(byte[] filter)1187         public void installPacketFilter(byte[] filter) {
1188             sendMessage(CMD_INSTALL_PACKET_FILTER, filter);
1189         }
1190 
1191         @Override
setFallbackMulticastFilter(boolean enabled)1192         public void setFallbackMulticastFilter(boolean enabled) {
1193             sendMessage(CMD_SET_FALLBACK_PACKET_FILTERING, enabled);
1194         }
1195 
1196         @Override
setNeighborDiscoveryOffload(boolean enabled)1197         public void setNeighborDiscoveryOffload(boolean enabled) {
1198             sendMessage(CMD_CONFIG_ND_OFFLOAD, (enabled ? 1 : 0));
1199         }
1200     }
1201 
stopIpManager()1202     private void stopIpManager() {
1203         /* Restore power save and suspend optimizations */
1204         handlePostDhcpSetup();
1205         mIpManager.stop();
1206     }
1207 
getPrivateBroadcast(String action, int requestCode)1208     PendingIntent getPrivateBroadcast(String action, int requestCode) {
1209         Intent intent = new Intent(action, null);
1210         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1211         intent.setPackage("android");
1212         return mFacade.getBroadcast(mContext, requestCode, intent, 0);
1213     }
1214 
1215     /**
1216      * Set wpa_supplicant log level using |mVerboseLoggingLevel| flag.
1217      */
setSupplicantLogLevel()1218     void setSupplicantLogLevel() {
1219         mWifiNative.setSupplicantLogLevel(mVerboseLoggingEnabled);
1220     }
1221 
1222     /**
1223      * Method to update logging level in wifi service related classes.
1224      *
1225      * @param verbose int logging level to use
1226      */
enableVerboseLogging(int verbose)1227     public void enableVerboseLogging(int verbose) {
1228         if (verbose > 0) {
1229             mVerboseLoggingEnabled = true;
1230             setLogRecSize(ActivityManager.isLowRamDeviceStatic()
1231                     ? NUM_LOG_RECS_VERBOSE_LOW_MEMORY : NUM_LOG_RECS_VERBOSE);
1232         } else {
1233             mVerboseLoggingEnabled = false;
1234             setLogRecSize(NUM_LOG_RECS_NORMAL);
1235         }
1236         configureVerboseHalLogging(mVerboseLoggingEnabled);
1237         setSupplicantLogLevel();
1238         mCountryCode.enableVerboseLogging(verbose);
1239         mWifiScoreReport.enableVerboseLogging(mVerboseLoggingEnabled);
1240         mWifiDiagnostics.startLogging(mVerboseLoggingEnabled);
1241         mWifiMonitor.enableVerboseLogging(verbose);
1242         mWifiNative.enableVerboseLogging(verbose);
1243         mWifiConfigManager.enableVerboseLogging(verbose);
1244         mSupplicantStateTracker.enableVerboseLogging(verbose);
1245     }
1246 
1247     private static final String SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL = "log.tag.WifiHAL";
1248     private static final String LOGD_LEVEL_DEBUG = "D";
1249     private static final String LOGD_LEVEL_VERBOSE = "V";
configureVerboseHalLogging(boolean enableVerbose)1250     private void configureVerboseHalLogging(boolean enableVerbose) {
1251         if (mBuildProperties.isUserBuild()) {  // Verbose HAL logging not supported on user builds.
1252             return;
1253         }
1254         mPropertyService.set(SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL,
1255                 enableVerbose ? LOGD_LEVEL_VERBOSE : LOGD_LEVEL_DEBUG);
1256     }
1257 
1258     private int mAggressiveHandover = 0;
1259 
getAggressiveHandover()1260     int getAggressiveHandover() {
1261         return mAggressiveHandover;
1262     }
1263 
enableAggressiveHandover(int enabled)1264     void enableAggressiveHandover(int enabled) {
1265         mAggressiveHandover = enabled;
1266     }
1267 
clearANQPCache()1268     public void clearANQPCache() {
1269         // TODO(b/31065385)
1270         // mWifiConfigManager.trimANQPCache(true);
1271     }
1272 
setAllowScansWithTraffic(int enabled)1273     public void setAllowScansWithTraffic(int enabled) {
1274         mAlwaysEnableScansWhileAssociated = enabled;
1275     }
1276 
getAllowScansWithTraffic()1277     public int getAllowScansWithTraffic() {
1278         return mAlwaysEnableScansWhileAssociated;
1279     }
1280 
1281     /*
1282      * Dynamically turn on/off if switching networks while connected is allowd.
1283      */
setEnableAutoJoinWhenAssociated(boolean enabled)1284     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
1285         sendMessage(CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED, enabled ? 1 : 0);
1286         return true;
1287     }
1288 
getEnableAutoJoinWhenAssociated()1289     public boolean getEnableAutoJoinWhenAssociated() {
1290         return mEnableAutoJoinWhenAssociated;
1291     }
1292 
setRandomMacOui()1293     private boolean setRandomMacOui() {
1294         String oui = mContext.getResources().getString(R.string.config_wifi_random_mac_oui);
1295         if (TextUtils.isEmpty(oui)) {
1296             oui = GOOGLE_OUI;
1297         }
1298         String[] ouiParts = oui.split("-");
1299         byte[] ouiBytes = new byte[3];
1300         ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF);
1301         ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF);
1302         ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF);
1303 
1304         logd("Setting OUI to " + oui);
1305         return mWifiNative.setScanningMacOui(ouiBytes);
1306     }
1307 
1308     /**
1309      * Helper method to lookup the framework network ID of the network currently configured in
1310      * wpa_supplicant using the provided supplicant network ID. This is needed for translating the
1311      * networkID received from all {@link WifiMonitor} events.
1312      *
1313      * @param supplicantNetworkId Network ID of network in wpa_supplicant.
1314      * @return Corresponding Internal configured network ID
1315      * TODO(b/31080843): This is ugly! We need to hide this translation of networkId's. This will
1316      * be handled once we move all of this connection logic to wificond.
1317      */
lookupFrameworkNetworkId(int supplicantNetworkId)1318     private int lookupFrameworkNetworkId(int supplicantNetworkId) {
1319         return mWifiNative.getFrameworkNetworkId(supplicantNetworkId);
1320     }
1321 
1322     /**
1323      * Initiates connection to a network specified by the user/app. This method checks if the
1324      * requesting app holds the NETWORK_SETTINGS permission.
1325      *
1326      * @param netId Id network to initiate connection.
1327      * @param uid UID of the app requesting the connection.
1328      * @param forceReconnect Whether to force a connection even if we're connected to the same
1329      *                       network currently.
1330      */
connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect)1331     private boolean connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) {
1332         logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid
1333                 + ", forceReconnect = " + forceReconnect);
1334         if (mWifiConfigManager.getConfiguredNetwork(netId) == null) {
1335             loge("connectToUserSelectNetwork Invalid network Id=" + netId);
1336             return false;
1337         }
1338         if (!mWifiConfigManager.enableNetwork(netId, true, uid)
1339                 || !mWifiConfigManager.checkAndUpdateLastConnectUid(netId, uid)) {
1340             logi("connectToUserSelectNetwork Allowing uid " + uid
1341                     + " with insufficient permissions to connect=" + netId);
1342         } else {
1343             // Note user connect choice here, so that it will be considered in the next network
1344             // selection.
1345             mWifiConnectivityManager.setUserConnectChoice(netId);
1346         }
1347         if (!forceReconnect && mWifiInfo.getNetworkId() == netId) {
1348             // We're already connected to the user specified network, don't trigger a
1349             // reconnection unless it was forced.
1350             logi("connectToUserSelectNetwork already connecting/connected=" + netId);
1351         } else {
1352             mWifiConnectivityManager.prepareForForcedConnection(netId);
1353             startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
1354         }
1355         return true;
1356     }
1357 
1358     /**
1359      * ******************************************************
1360      * Methods exposed for public use
1361      * ******************************************************
1362      */
1363 
getMessenger()1364     public Messenger getMessenger() {
1365         return new Messenger(getHandler());
1366     }
1367 
1368     /**
1369      * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
1370      * given to callingUid.
1371      *
1372      * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
1373      *                   workSource is specified.
1374      * @param workSource If not null, blame is given to workSource.
1375      * @param settings   Scan settings, see {@link ScanSettings}.
1376      */
startScan(int callingUid, int scanCounter, ScanSettings settings, WorkSource workSource)1377     public void startScan(int callingUid, int scanCounter,
1378                           ScanSettings settings, WorkSource workSource) {
1379         Bundle bundle = new Bundle();
1380         bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
1381         bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1382         bundle.putLong(SCAN_REQUEST_TIME, mClock.getWallClockMillis());
1383         sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
1384     }
1385 
1386     private long mDisconnectedTimeStamp = 0;
1387 
getDisconnectedTimeMilli()1388     public long getDisconnectedTimeMilli() {
1389         if (getCurrentState() == mDisconnectedState
1390                 && mDisconnectedTimeStamp != 0) {
1391             long now_ms = mClock.getWallClockMillis();
1392             return now_ms - mDisconnectedTimeStamp;
1393         }
1394         return 0;
1395     }
1396 
1397     // Last connect attempt is used to prevent scan requests:
1398     //  - for a period of 10 seconds after attempting to connect
1399     private long lastConnectAttemptTimestamp = 0;
1400     private Set<Integer> lastScanFreqs = null;
1401 
1402     // For debugging, keep track of last message status handling
1403     // TODO, find an equivalent mechanism as part of parent class
1404     private static final int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
1405     private static final int MESSAGE_HANDLING_STATUS_OK = 1;
1406     private static final int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
1407     private static final int MESSAGE_HANDLING_STATUS_REFUSED = -1;
1408     private static final int MESSAGE_HANDLING_STATUS_FAIL = -2;
1409     private static final int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
1410     private static final int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
1411     private static final int MESSAGE_HANDLING_STATUS_DISCARD = -5;
1412     private static final int MESSAGE_HANDLING_STATUS_LOOPED = -6;
1413     private static final int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
1414 
1415     private int messageHandlingStatus = 0;
1416 
1417     //TODO: this is used only to track connection attempts, however the link state and packet per
1418     //TODO: second logic should be folded into that
checkOrDeferScanAllowed(Message msg)1419     private boolean checkOrDeferScanAllowed(Message msg) {
1420         long now = mClock.getWallClockMillis();
1421         if (lastConnectAttemptTimestamp != 0 && (now - lastConnectAttemptTimestamp) < 10000) {
1422             Message dmsg = Message.obtain(msg);
1423             sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttemptTimestamp));
1424             return false;
1425         }
1426         return true;
1427     }
1428 
1429     private int mOnTime = 0;
1430     private int mTxTime = 0;
1431     private int mRxTime = 0;
1432 
1433     private int mOnTimeScreenStateChange = 0;
1434     private long lastOntimeReportTimeStamp = 0;
1435     private long lastScreenStateChangeTimeStamp = 0;
1436     private int mOnTimeLastReport = 0;
1437     private int mTxTimeLastReport = 0;
1438     private int mRxTimeLastReport = 0;
1439 
1440     private long lastLinkLayerStatsUpdate = 0;
1441 
reportOnTime()1442     String reportOnTime() {
1443         long now = mClock.getWallClockMillis();
1444         StringBuilder sb = new StringBuilder();
1445         // Report stats since last report
1446         int on = mOnTime - mOnTimeLastReport;
1447         mOnTimeLastReport = mOnTime;
1448         int tx = mTxTime - mTxTimeLastReport;
1449         mTxTimeLastReport = mTxTime;
1450         int rx = mRxTime - mRxTimeLastReport;
1451         mRxTimeLastReport = mRxTime;
1452         int period = (int) (now - lastOntimeReportTimeStamp);
1453         lastOntimeReportTimeStamp = now;
1454         sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
1455         // Report stats since Screen State Changed
1456         on = mOnTime - mOnTimeScreenStateChange;
1457         period = (int) (now - lastScreenStateChangeTimeStamp);
1458         sb.append(String.format(" from screen [on:%d period:%d]", on, period));
1459         return sb.toString();
1460     }
1461 
getWifiLinkLayerStats()1462     WifiLinkLayerStats getWifiLinkLayerStats() {
1463         WifiLinkLayerStats stats = null;
1464         if (mWifiLinkLayerStatsSupported > 0) {
1465             String name = "wlan0";
1466             stats = mWifiNative.getWifiLinkLayerStats(name);
1467             if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
1468                 mWifiLinkLayerStatsSupported -= 1;
1469             } else if (stats != null) {
1470                 lastLinkLayerStatsUpdate = mClock.getWallClockMillis();
1471                 mOnTime = stats.on_time;
1472                 mTxTime = stats.tx_time;
1473                 mRxTime = stats.rx_time;
1474                 mRunningBeaconCount = stats.beacon_rx;
1475             }
1476         }
1477         if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
1478             long mTxPkts = mFacade.getTxPackets(mInterfaceName);
1479             long mRxPkts = mFacade.getRxPackets(mInterfaceName);
1480             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
1481         } else {
1482             mWifiInfo.updatePacketRates(stats, lastLinkLayerStatsUpdate);
1483         }
1484         return stats;
1485     }
1486 
startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds)1487     int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds) {
1488         int ret = mWifiNative.startSendingOffloadedPacket(slot, packetData, intervalSeconds * 1000);
1489         if (ret != 0) {
1490             loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds +
1491                     "): hardware error " + ret);
1492             return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
1493         } else {
1494             return ConnectivityManager.PacketKeepalive.SUCCESS;
1495         }
1496     }
1497 
stopWifiIPPacketOffload(int slot)1498     int stopWifiIPPacketOffload(int slot) {
1499         int ret = mWifiNative.stopSendingOffloadedPacket(slot);
1500         if (ret != 0) {
1501             loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret);
1502             return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
1503         } else {
1504             return ConnectivityManager.PacketKeepalive.SUCCESS;
1505         }
1506     }
1507 
startRssiMonitoringOffload(byte maxRssi, byte minRssi)1508     int startRssiMonitoringOffload(byte maxRssi, byte minRssi) {
1509         return mWifiNative.startRssiMonitoring(maxRssi, minRssi, WifiStateMachine.this);
1510     }
1511 
stopRssiMonitoringOffload()1512     int stopRssiMonitoringOffload() {
1513         return mWifiNative.stopRssiMonitoring();
1514     }
1515 
handleScanRequest(Message message)1516     private void handleScanRequest(Message message) {
1517         ScanSettings settings = null;
1518         WorkSource workSource = null;
1519 
1520         // unbundle parameters
1521         Bundle bundle = (Bundle) message.obj;
1522 
1523         if (bundle != null) {
1524             settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
1525             workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
1526         }
1527 
1528         Set<Integer> freqs = null;
1529         if (settings != null && settings.channelSet != null) {
1530             freqs = new HashSet<>();
1531             for (WifiChannel channel : settings.channelSet) {
1532                 freqs.add(channel.freqMHz);
1533             }
1534         }
1535 
1536         // Retrieve the list of hidden network SSIDs to scan for.
1537         List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks =
1538                 mWifiConfigManager.retrieveHiddenNetworkList();
1539 
1540         // call wifi native to start the scan
1541         if (startScanNative(freqs, hiddenNetworks, workSource)) {
1542             // a full scan covers everything, clearing scan request buffer
1543             if (freqs == null)
1544                 mBufferedScanMsg.clear();
1545             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
1546             return;
1547         }
1548 
1549         // if reach here, scan request is rejected
1550 
1551         if (!mIsScanOngoing) {
1552             // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
1553 
1554             // discard this request and pop up the next one
1555             if (mBufferedScanMsg.size() > 0) {
1556                 sendMessage(mBufferedScanMsg.remove());
1557             }
1558             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
1559         } else if (!mIsFullScanOngoing) {
1560             // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
1561             // buffer the scan request to make sure specified channels will be scanned eventually
1562             if (freqs == null)
1563                 mBufferedScanMsg.clear();
1564             if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
1565                 Message msg = obtainMessage(CMD_START_SCAN,
1566                         message.arg1, message.arg2, bundle);
1567                 mBufferedScanMsg.add(msg);
1568             } else {
1569                 // if too many requests in buffer, combine them into a single full scan
1570                 bundle = new Bundle();
1571                 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
1572                 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1573                 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
1574                 mBufferedScanMsg.clear();
1575                 mBufferedScanMsg.add(msg);
1576             }
1577             messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
1578         } else {
1579             // mIsScanOngoing and mIsFullScanOngoing
1580             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
1581         }
1582     }
1583 
1584 
1585     // TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
1586     // scan functionality is refactored out of WifiStateMachine.
1587     /**
1588      * return true iff scan request is accepted
1589      */
startScanNative(final Set<Integer> freqs, List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList, WorkSource workSource)1590     private boolean startScanNative(final Set<Integer> freqs,
1591             List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList,
1592             WorkSource workSource) {
1593         WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
1594         if (freqs == null) {
1595             settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
1596         } else {
1597             settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
1598             int index = 0;
1599             settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
1600             for (Integer freq : freqs) {
1601                 settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
1602             }
1603         }
1604         settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
1605                 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
1606 
1607         settings.hiddenNetworks =
1608                 hiddenNetworkList.toArray(
1609                         new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
1610 
1611         WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
1612                 // ignore all events since WifiStateMachine is registered for the supplicant events
1613                 @Override
1614                 public void onSuccess() {
1615                 }
1616                 @Override
1617                 public void onFailure(int reason, String description) {
1618                     mIsScanOngoing = false;
1619                     mIsFullScanOngoing = false;
1620                 }
1621                 @Override
1622                 public void onResults(WifiScanner.ScanData[] results) {
1623                 }
1624                 @Override
1625                 public void onFullResult(ScanResult fullScanResult) {
1626                 }
1627                 @Override
1628                 public void onPeriodChanged(int periodInMs) {
1629                 }
1630             };
1631         mWifiScanner.startScan(settings, nativeScanListener, workSource);
1632         mIsScanOngoing = true;
1633         mIsFullScanOngoing = (freqs == null);
1634         lastScanFreqs = freqs;
1635         return true;
1636     }
1637 
1638     /**
1639      * TODO: doc
1640      */
setSupplicantRunning(boolean enable)1641     public void setSupplicantRunning(boolean enable) {
1642         if (enable) {
1643             sendMessage(CMD_START_SUPPLICANT);
1644         } else {
1645             sendMessage(CMD_STOP_SUPPLICANT);
1646         }
1647     }
1648 
1649     /**
1650      * TODO: doc
1651      */
setHostApRunning(SoftApModeConfiguration wifiConfig, boolean enable)1652     public void setHostApRunning(SoftApModeConfiguration wifiConfig, boolean enable) {
1653         if (enable) {
1654             sendMessage(CMD_START_AP, wifiConfig);
1655         } else {
1656             sendMessage(CMD_STOP_AP);
1657         }
1658     }
1659 
setWifiApConfiguration(WifiConfiguration config)1660     public void setWifiApConfiguration(WifiConfiguration config) {
1661         mWifiApConfigStore.setApConfiguration(config);
1662     }
1663 
syncGetWifiApConfiguration()1664     public WifiConfiguration syncGetWifiApConfiguration() {
1665         return mWifiApConfigStore.getApConfiguration();
1666     }
1667 
1668     /**
1669      * TODO: doc
1670      */
syncGetWifiState()1671     public int syncGetWifiState() {
1672         return mWifiState.get();
1673     }
1674 
1675     /**
1676      * TODO: doc
1677      */
syncGetWifiStateByName()1678     public String syncGetWifiStateByName() {
1679         switch (mWifiState.get()) {
1680             case WIFI_STATE_DISABLING:
1681                 return "disabling";
1682             case WIFI_STATE_DISABLED:
1683                 return "disabled";
1684             case WIFI_STATE_ENABLING:
1685                 return "enabling";
1686             case WIFI_STATE_ENABLED:
1687                 return "enabled";
1688             case WIFI_STATE_UNKNOWN:
1689                 return "unknown state";
1690             default:
1691                 return "[invalid state]";
1692         }
1693     }
1694 
1695     /**
1696      * TODO: doc
1697      */
syncGetWifiApState()1698     public int syncGetWifiApState() {
1699         return mWifiApState.get();
1700     }
1701 
1702     /**
1703      * TODO: doc
1704      */
syncGetWifiApStateByName()1705     public String syncGetWifiApStateByName() {
1706         switch (mWifiApState.get()) {
1707             case WIFI_AP_STATE_DISABLING:
1708                 return "disabling";
1709             case WIFI_AP_STATE_DISABLED:
1710                 return "disabled";
1711             case WIFI_AP_STATE_ENABLING:
1712                 return "enabling";
1713             case WIFI_AP_STATE_ENABLED:
1714                 return "enabled";
1715             case WIFI_AP_STATE_FAILED:
1716                 return "failed";
1717             default:
1718                 return "[invalid state]";
1719         }
1720     }
1721 
isConnected()1722     public boolean isConnected() {
1723         return getCurrentState() == mConnectedState;
1724     }
1725 
isDisconnected()1726     public boolean isDisconnected() {
1727         return getCurrentState() == mDisconnectedState;
1728     }
1729 
isSupplicantTransientState()1730     public boolean isSupplicantTransientState() {
1731         SupplicantState supplicantState = mWifiInfo.getSupplicantState();
1732         if (supplicantState == SupplicantState.ASSOCIATING
1733                 || supplicantState == SupplicantState.AUTHENTICATING
1734                 || supplicantState == SupplicantState.FOUR_WAY_HANDSHAKE
1735                 || supplicantState == SupplicantState.GROUP_HANDSHAKE) {
1736 
1737             if (mVerboseLoggingEnabled) {
1738                 Log.d(TAG, "Supplicant is under transient state: " + supplicantState);
1739             }
1740             return true;
1741         } else {
1742             if (mVerboseLoggingEnabled) {
1743                 Log.d(TAG, "Supplicant is under steady state: " + supplicantState);
1744             }
1745         }
1746 
1747         return false;
1748     }
1749 
isLinkDebouncing()1750     public boolean isLinkDebouncing() {
1751         return mIsLinkDebouncing;
1752     }
1753 
1754     /**
1755      * Get status information for the current connection, if any.
1756      *
1757      * @return a {@link WifiInfo} object containing information about the current connection
1758      */
syncRequestConnectionInfo(String callingPackage)1759     public WifiInfo syncRequestConnectionInfo(String callingPackage) {
1760         int uid = Binder.getCallingUid();
1761         WifiInfo result = new WifiInfo(mWifiInfo);
1762         if (uid == Process.myUid()) return result;
1763         boolean hideBssidAndSsid = true;
1764         result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
1765 
1766         IPackageManager packageManager = AppGlobals.getPackageManager();
1767 
1768         try {
1769             if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
1770                     uid) == PackageManager.PERMISSION_GRANTED) {
1771                 result.setMacAddress(mWifiInfo.getMacAddress());
1772             }
1773             final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration();
1774             if (mWifiPermissionsUtil.canAccessFullConnectionInfo(
1775                     currentWifiConfiguration,
1776                     callingPackage,
1777                     uid,
1778                     Build.VERSION_CODES.O)) {
1779                 hideBssidAndSsid = false;
1780             }
1781         } catch (RemoteException e) {
1782             Log.e(TAG, "Error checking receiver permission", e);
1783         } catch (SecurityException e) {
1784             Log.e(TAG, "Security exception checking receiver permission", e);
1785         }
1786         if (hideBssidAndSsid) {
1787             result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS);
1788             result.setSSID(WifiSsid.createFromHex(null));
1789         }
1790         return result;
1791     }
1792 
getWifiInfo()1793     public WifiInfo getWifiInfo() {
1794         return mWifiInfo;
1795     }
1796 
syncGetDhcpResults()1797     public DhcpResults syncGetDhcpResults() {
1798         synchronized (mDhcpResultsLock) {
1799             return new DhcpResults(mDhcpResults);
1800         }
1801     }
1802 
1803     /**
1804      * TODO: doc
1805      */
setOperationalMode(int mode)1806     public void setOperationalMode(int mode) {
1807         if (mVerboseLoggingEnabled) log("setting operational mode to " + String.valueOf(mode));
1808         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
1809     }
1810 
1811     /**
1812      * Allow tests to confirm the operational mode for WSM.
1813      */
1814     @VisibleForTesting
getOperationalModeForTest()1815     protected int getOperationalModeForTest() {
1816         return mOperationalMode;
1817     }
1818 
1819     /**
1820      * TODO: doc
1821      */
syncGetScanResultsList()1822     public List<ScanResult> syncGetScanResultsList() {
1823         synchronized (mScanResultsLock) {
1824             List<ScanResult> scanList = new ArrayList<>();
1825             for (ScanDetail result : mScanResults) {
1826                 scanList.add(new ScanResult(result.getScanResult()));
1827             }
1828             return scanList;
1829         }
1830     }
1831 
syncQueryPasspointIcon(AsyncChannel channel, long bssid, String fileName)1832     public boolean syncQueryPasspointIcon(AsyncChannel channel, long bssid, String fileName) {
1833         Bundle bundle = new Bundle();
1834         bundle.putLong(EXTRA_OSU_ICON_QUERY_BSSID, bssid);
1835         bundle.putString(EXTRA_OSU_ICON_QUERY_FILENAME, fileName);
1836         Message resultMsg = channel.sendMessageSynchronously(CMD_QUERY_OSU_ICON, bundle);
1837         int result = resultMsg.arg1;
1838         resultMsg.recycle();
1839         return result == 1;
1840     }
1841 
matchProviderWithCurrentNetwork(AsyncChannel channel, String fqdn)1842     public int matchProviderWithCurrentNetwork(AsyncChannel channel, String fqdn) {
1843         Message resultMsg = channel.sendMessageSynchronously(CMD_MATCH_PROVIDER_NETWORK, fqdn);
1844         int result = resultMsg.arg1;
1845         resultMsg.recycle();
1846         return result;
1847     }
1848 
1849     /**
1850      * Deauthenticate and set the re-authentication hold off time for the current network
1851      * @param holdoff hold off time in milliseconds
1852      * @param ess set if the hold off pertains to an ESS rather than a BSS
1853      */
deauthenticateNetwork(AsyncChannel channel, long holdoff, boolean ess)1854     public void deauthenticateNetwork(AsyncChannel channel, long holdoff, boolean ess) {
1855         // TODO: This needs an implementation
1856     }
1857 
disableEphemeralNetwork(String SSID)1858     public void disableEphemeralNetwork(String SSID) {
1859         if (SSID != null) {
1860             sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID);
1861         }
1862     }
1863 
1864     /**
1865      * Disconnect from Access Point
1866      */
disconnectCommand()1867     public void disconnectCommand() {
1868         sendMessage(CMD_DISCONNECT);
1869     }
1870 
disconnectCommand(int uid, int reason)1871     public void disconnectCommand(int uid, int reason) {
1872         sendMessage(CMD_DISCONNECT, uid, reason);
1873     }
1874 
1875     /**
1876      * Initiate a reconnection to AP
1877      */
reconnectCommand(WorkSource workSource)1878     public void reconnectCommand(WorkSource workSource) {
1879         sendMessage(CMD_RECONNECT, workSource);
1880     }
1881 
1882     /**
1883      * Initiate a re-association to AP
1884      */
reassociateCommand()1885     public void reassociateCommand() {
1886         sendMessage(CMD_REASSOCIATE);
1887     }
1888 
1889     /**
1890      * Reload networks and then reconnect; helps load correct data for TLS networks
1891      */
1892 
reloadTlsNetworksAndReconnect()1893     public void reloadTlsNetworksAndReconnect() {
1894         sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
1895     }
1896 
1897     /**
1898      * Add a network synchronously
1899      *
1900      * @return network id of the new network
1901      */
syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config)1902     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
1903         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
1904         int result = resultMsg.arg1;
1905         resultMsg.recycle();
1906         return result;
1907     }
1908 
1909     /**
1910      * Get configured networks synchronously
1911      *
1912      * @param channel
1913      * @return
1914      */
1915 
syncGetConfiguredNetworks(int uuid, AsyncChannel channel)1916     public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
1917         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
1918         if (resultMsg == null) { // an error has occurred
1919             return null;
1920         } else {
1921             List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
1922             resultMsg.recycle();
1923             return result;
1924         }
1925     }
1926 
syncGetPrivilegedConfiguredNetwork(AsyncChannel channel)1927     public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
1928         Message resultMsg = channel.sendMessageSynchronously(
1929                 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS);
1930         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
1931         resultMsg.recycle();
1932         return result;
1933     }
1934 
syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel)1935     public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) {
1936         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult);
1937         WifiConfiguration config = (WifiConfiguration) resultMsg.obj;
1938         resultMsg.recycle();
1939         return config;
1940     }
1941 
1942     /**
1943      * Retrieve a list of {@link OsuProvider} associated with the given AP synchronously.
1944      *
1945      * @param scanResult The scan result of the AP
1946      * @param channel Channel for communicating with the state machine
1947      * @return List of {@link OsuProvider}
1948      */
syncGetMatchingOsuProviders(ScanResult scanResult, AsyncChannel channel)1949     public List<OsuProvider> syncGetMatchingOsuProviders(ScanResult scanResult,
1950             AsyncChannel channel) {
1951         Message resultMsg =
1952                 channel.sendMessageSynchronously(CMD_GET_MATCHING_OSU_PROVIDERS, scanResult);
1953         List<OsuProvider> providers = (List<OsuProvider>) resultMsg.obj;
1954         resultMsg.recycle();
1955         return providers;
1956     }
1957 
1958     /**
1959      * Add or update a Passpoint configuration synchronously.
1960      *
1961      * @param channel Channel for communicating with the state machine
1962      * @param config The configuration to add or update
1963      * @return true on success
1964      */
syncAddOrUpdatePasspointConfig(AsyncChannel channel, PasspointConfiguration config, int uid)1965     public boolean syncAddOrUpdatePasspointConfig(AsyncChannel channel,
1966             PasspointConfiguration config, int uid) {
1967         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_PASSPOINT_CONFIG,
1968                 uid, 0, config);
1969         boolean result = (resultMsg.arg1 == SUCCESS);
1970         resultMsg.recycle();
1971         return result;
1972     }
1973 
1974     /**
1975      * Remove a Passpoint configuration synchronously.
1976      *
1977      * @param channel Channel for communicating with the state machine
1978      * @param fqdn The FQDN of the Passpoint configuration to remove
1979      * @return true on success
1980      */
syncRemovePasspointConfig(AsyncChannel channel, String fqdn)1981     public boolean syncRemovePasspointConfig(AsyncChannel channel, String fqdn) {
1982         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_PASSPOINT_CONFIG,
1983                 fqdn);
1984         boolean result = (resultMsg.arg1 == SUCCESS);
1985         resultMsg.recycle();
1986         return result;
1987     }
1988 
1989     /**
1990      * Get the list of installed Passpoint configurations synchronously.
1991      *
1992      * @param channel Channel for communicating with the state machine
1993      * @return List of {@link PasspointConfiguration}
1994      */
syncGetPasspointConfigs(AsyncChannel channel)1995     public List<PasspointConfiguration> syncGetPasspointConfigs(AsyncChannel channel) {
1996         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_PASSPOINT_CONFIGS);
1997         List<PasspointConfiguration> result = (List<PasspointConfiguration>) resultMsg.obj;
1998         resultMsg.recycle();
1999         return result;
2000     }
2001 
2002     /**
2003      * Get connection statistics synchronously
2004      *
2005      * @param channel
2006      * @return
2007      */
2008 
syncGetConnectionStatistics(AsyncChannel channel)2009     public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) {
2010         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS);
2011         WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj;
2012         resultMsg.recycle();
2013         return result;
2014     }
2015 
2016     /**
2017      * Get adaptors synchronously
2018      */
2019 
syncGetSupportedFeatures(AsyncChannel channel)2020     public int syncGetSupportedFeatures(AsyncChannel channel) {
2021         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
2022         int supportedFeatureSet = resultMsg.arg1;
2023         resultMsg.recycle();
2024 
2025         // Mask the feature set against system properties.
2026         boolean disableRtt = mPropertyService.getBoolean("config.disable_rtt", false);
2027         if (disableRtt) {
2028             supportedFeatureSet &=
2029                     ~(WifiManager.WIFI_FEATURE_D2D_RTT | WifiManager.WIFI_FEATURE_D2AP_RTT);
2030         }
2031 
2032         return supportedFeatureSet;
2033     }
2034 
2035     /**
2036      * Get link layers stats for adapter synchronously
2037      */
syncGetLinkLayerStats(AsyncChannel channel)2038     public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
2039         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
2040         WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
2041         resultMsg.recycle();
2042         return result;
2043     }
2044 
2045     /**
2046      * Delete a network
2047      *
2048      * @param networkId id of the network to be removed
2049      */
syncRemoveNetwork(AsyncChannel channel, int networkId)2050     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
2051         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
2052         boolean result = (resultMsg.arg1 != FAILURE);
2053         resultMsg.recycle();
2054         return result;
2055     }
2056 
2057     /**
2058      * Enable a network
2059      *
2060      * @param netId         network id of the network
2061      * @param disableOthers true, if all other networks have to be disabled
2062      * @return {@code true} if the operation succeeds, {@code false} otherwise
2063      */
syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers)2064     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
2065         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
2066                 disableOthers ? 1 : 0);
2067         boolean result = (resultMsg.arg1 != FAILURE);
2068         resultMsg.recycle();
2069         return result;
2070     }
2071 
2072     /**
2073      * Disable a network
2074      *
2075      * @param netId network id of the network
2076      * @return {@code true} if the operation succeeds, {@code false} otherwise
2077      */
syncDisableNetwork(AsyncChannel channel, int netId)2078     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
2079         Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
2080         boolean result = (resultMsg.what != WifiManager.DISABLE_NETWORK_FAILED);
2081         resultMsg.recycle();
2082         return result;
2083     }
2084 
2085     /**
2086      * Retrieves a WPS-NFC configuration token for the specified network
2087      *
2088      * @return a hex string representation of the WPS-NFC configuration token
2089      */
syncGetCurrentNetworkWpsNfcConfigurationToken()2090     public String syncGetCurrentNetworkWpsNfcConfigurationToken() {
2091         return mWifiNative.getCurrentNetworkWpsNfcConfigurationToken();
2092     }
2093 
enableRssiPolling(boolean enabled)2094     public void enableRssiPolling(boolean enabled) {
2095         sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
2096     }
2097 
2098     /**
2099      * Start filtering Multicast v4 packets
2100      */
startFilteringMulticastPackets()2101     public void startFilteringMulticastPackets() {
2102         mIpManager.setMulticastFilter(true);
2103     }
2104 
2105     /**
2106      * Stop filtering Multicast v4 packets
2107      */
stopFilteringMulticastPackets()2108     public void stopFilteringMulticastPackets() {
2109         mIpManager.setMulticastFilter(false);
2110     }
2111 
2112     /**
2113      * Set high performance mode of operation.
2114      * Enabling would set active power mode and disable suspend optimizations;
2115      * disabling would set auto power mode and enable suspend optimizations
2116      *
2117      * @param enable true if enable, false otherwise
2118      */
setHighPerfModeEnabled(boolean enable)2119     public void setHighPerfModeEnabled(boolean enable) {
2120         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
2121     }
2122 
2123 
2124     /**
2125      * reset cached SIM credential data
2126      */
resetSimAuthNetworks(boolean simPresent)2127     public synchronized void resetSimAuthNetworks(boolean simPresent) {
2128         sendMessage(CMD_RESET_SIM_NETWORKS, simPresent ? 1 : 0);
2129     }
2130 
2131     /**
2132      * Get Network object of current wifi network
2133      * @return Network object of current wifi network
2134      */
getCurrentNetwork()2135     public Network getCurrentNetwork() {
2136         if (mNetworkAgent != null) {
2137             return new Network(mNetworkAgent.netId);
2138         } else {
2139             return null;
2140         }
2141     }
2142 
2143     /**
2144      * Enable TDLS for a specific MAC address
2145      */
enableTdls(String remoteMacAddress, boolean enable)2146     public void enableTdls(String remoteMacAddress, boolean enable) {
2147         int enabler = enable ? 1 : 0;
2148         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
2149     }
2150 
2151     /**
2152      * Send a message indicating bluetooth adapter connection state changed
2153      */
sendBluetoothAdapterStateChange(int state)2154     public void sendBluetoothAdapterStateChange(int state) {
2155         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
2156     }
2157 
2158     /**
2159      * Send a message indicating a package has been uninstalled.
2160      */
removeAppConfigs(String packageName, int uid)2161     public void removeAppConfigs(String packageName, int uid) {
2162         // Build partial AppInfo manually - package may not exist in database any more
2163         ApplicationInfo ai = new ApplicationInfo();
2164         ai.packageName = packageName;
2165         ai.uid = uid;
2166         sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai);
2167     }
2168 
2169     /**
2170      * Send a message indicating a user has been removed.
2171      */
removeUserConfigs(int userId)2172     public void removeUserConfigs(int userId) {
2173         sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId);
2174     }
2175 
2176     /**
2177      * Save configuration on supplicant
2178      *
2179      * @return {@code true} if the operation succeeds, {@code false} otherwise
2180      * <p/>
2181      * TODO: deprecate this
2182      */
syncSaveConfig(AsyncChannel channel)2183     public boolean syncSaveConfig(AsyncChannel channel) {
2184         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
2185         boolean result = (resultMsg.arg1 != FAILURE);
2186         resultMsg.recycle();
2187         return result;
2188     }
2189 
updateBatteryWorkSource(WorkSource newSource)2190     public void updateBatteryWorkSource(WorkSource newSource) {
2191         synchronized (mRunningWifiUids) {
2192             try {
2193                 if (newSource != null) {
2194                     mRunningWifiUids.set(newSource);
2195                 }
2196                 if (mIsRunning) {
2197                     if (mReportedRunning) {
2198                         // If the work source has changed since last time, need
2199                         // to remove old work from battery stats.
2200                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
2201                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
2202                                     mRunningWifiUids);
2203                             mLastRunningWifiUids.set(mRunningWifiUids);
2204                         }
2205                     } else {
2206                         // Now being started, report it.
2207                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
2208                         mLastRunningWifiUids.set(mRunningWifiUids);
2209                         mReportedRunning = true;
2210                     }
2211                 } else {
2212                     if (mReportedRunning) {
2213                         // Last reported we were running, time to stop.
2214                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
2215                         mLastRunningWifiUids.clear();
2216                         mReportedRunning = false;
2217                     }
2218                 }
2219                 mWakeLock.setWorkSource(newSource);
2220             } catch (RemoteException ignore) {
2221             }
2222         }
2223     }
2224 
dumpIpManager(FileDescriptor fd, PrintWriter pw, String[] args)2225     public void dumpIpManager(FileDescriptor fd, PrintWriter pw, String[] args) {
2226         mIpManager.dump(fd, pw, args);
2227     }
2228 
2229     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2230     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2231         super.dump(fd, pw, args);
2232         mSupplicantStateTracker.dump(fd, pw, args);
2233         pw.println("mLinkProperties " + mLinkProperties);
2234         pw.println("mWifiInfo " + mWifiInfo);
2235         pw.println("mDhcpResults " + mDhcpResults);
2236         pw.println("mNetworkInfo " + mNetworkInfo);
2237         pw.println("mLastSignalLevel " + mLastSignalLevel);
2238         pw.println("mLastBssid " + mLastBssid);
2239         pw.println("mLastNetworkId " + mLastNetworkId);
2240         pw.println("mOperationalMode " + mOperationalMode);
2241         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
2242         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2243         if (mCountryCode.getCountryCodeSentToDriver() != null) {
2244             pw.println("CountryCode sent to driver " + mCountryCode.getCountryCodeSentToDriver());
2245         } else {
2246             if (mCountryCode.getCountryCode() != null) {
2247                 pw.println("CountryCode: " +
2248                         mCountryCode.getCountryCode() + " was not sent to driver");
2249             } else {
2250                 pw.println("CountryCode was not initialized");
2251             }
2252         }
2253         if (mNetworkFactory != null) {
2254             mNetworkFactory.dump(fd, pw, args);
2255         } else {
2256             pw.println("mNetworkFactory is not initialized");
2257         }
2258 
2259         if (mUntrustedNetworkFactory != null) {
2260             mUntrustedNetworkFactory.dump(fd, pw, args);
2261         } else {
2262             pw.println("mUntrustedNetworkFactory is not initialized");
2263         }
2264         pw.println("Wlan Wake Reasons:" + mWifiNative.getWlanWakeReasonCount());
2265         pw.println();
2266 
2267         mWifiConfigManager.dump(fd, pw, args);
2268         pw.println();
2269         mPasspointManager.dump(pw);
2270         pw.println();
2271         mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_USER_ACTION);
2272         mWifiDiagnostics.dump(fd, pw, args);
2273         dumpIpManager(fd, pw, args);
2274         if (mWifiConnectivityManager != null) {
2275             mWifiConnectivityManager.dump(fd, pw, args);
2276         } else {
2277             pw.println("mWifiConnectivityManager is not initialized");
2278         }
2279     }
2280 
handleUserSwitch(int userId)2281     public void handleUserSwitch(int userId) {
2282         sendMessage(CMD_USER_SWITCH, userId);
2283     }
2284 
handleUserUnlock(int userId)2285     public void handleUserUnlock(int userId) {
2286         sendMessage(CMD_USER_UNLOCK, userId);
2287     }
2288 
handleUserStop(int userId)2289     public void handleUserStop(int userId) {
2290         sendMessage(CMD_USER_STOP, userId);
2291     }
2292 
2293     /**
2294      * ******************************************************
2295      * Internal private functions
2296      * ******************************************************
2297      */
2298 
logStateAndMessage(Message message, State state)2299     private void logStateAndMessage(Message message, State state) {
2300         messageHandlingStatus = 0;
2301         if (mVerboseLoggingEnabled) {
2302             logd(" " + state.getClass().getSimpleName() + " " + getLogRecString(message));
2303         }
2304     }
2305 
2306     @Override
recordLogRec(Message msg)2307     protected boolean recordLogRec(Message msg) {
2308         switch (msg.what) {
2309             case CMD_RSSI_POLL:
2310                 return mVerboseLoggingEnabled;
2311             default:
2312                 return true;
2313         }
2314     }
2315 
2316     /**
2317      * Return the additional string to be logged by LogRec, default
2318      *
2319      * @param msg that was processed
2320      * @return information to be logged as a String
2321      */
2322     @Override
getLogRecString(Message msg)2323     protected String getLogRecString(Message msg) {
2324         WifiConfiguration config;
2325         Long now;
2326         String report;
2327         String key;
2328         StringBuilder sb = new StringBuilder();
2329         if (mScreenOn) {
2330             sb.append("!");
2331         }
2332         if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
2333             sb.append("(").append(messageHandlingStatus).append(")");
2334         }
2335         sb.append(smToString(msg));
2336         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
2337             sb.append(" uid=" + msg.sendingUid);
2338         }
2339         sb.append(" rt=").append(mClock.getUptimeSinceBootMillis());
2340         sb.append("/").append(mClock.getElapsedSinceBootMillis());
2341         switch (msg.what) {
2342             case CMD_START_SCAN:
2343                 now = mClock.getWallClockMillis();
2344                 sb.append(" ");
2345                 sb.append(Integer.toString(msg.arg1));
2346                 sb.append(" ");
2347                 sb.append(Integer.toString(msg.arg2));
2348                 sb.append(" ic=");
2349                 sb.append(Integer.toString(sScanAlarmIntentCount));
2350                 if (msg.obj != null) {
2351                     Bundle bundle = (Bundle) msg.obj;
2352                     Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
2353                     if (request != 0) {
2354                         sb.append(" proc(ms):").append(now - request);
2355                     }
2356                 }
2357                 if (mIsScanOngoing) sb.append(" onGoing");
2358                 if (mIsFullScanOngoing) sb.append(" full");
2359                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2360                 sb.append(" f=").append(mWifiInfo.getFrequency());
2361                 sb.append(" sc=").append(mWifiInfo.score);
2362                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2363                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2364                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2365                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2366                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2367                 if (lastScanFreqs != null) {
2368                     sb.append(" list=");
2369                     for(int freq : lastScanFreqs) {
2370                         sb.append(freq).append(",");
2371                     }
2372                 }
2373                 report = reportOnTime();
2374                 if (report != null) {
2375                     sb.append(" ").append(report);
2376                 }
2377                 break;
2378             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2379                 sb.append(" ");
2380                 sb.append(Integer.toString(msg.arg1));
2381                 sb.append(" ");
2382                 sb.append(Integer.toString(msg.arg2));
2383                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
2384                 if (stateChangeResult != null) {
2385                     sb.append(stateChangeResult.toString());
2386                 }
2387                 break;
2388             case WifiManager.SAVE_NETWORK:
2389                 sb.append(" ");
2390                 sb.append(Integer.toString(msg.arg1));
2391                 sb.append(" ");
2392                 sb.append(Integer.toString(msg.arg2));
2393                 config = (WifiConfiguration) msg.obj;
2394                 if (config != null) {
2395                     sb.append(" ").append(config.configKey());
2396                     sb.append(" nid=").append(config.networkId);
2397                     if (config.hiddenSSID) {
2398                         sb.append(" hidden");
2399                     }
2400                     if (config.preSharedKey != null
2401                             && !config.preSharedKey.equals("*")) {
2402                         sb.append(" hasPSK");
2403                     }
2404                     if (config.ephemeral) {
2405                         sb.append(" ephemeral");
2406                     }
2407                     if (config.selfAdded) {
2408                         sb.append(" selfAdded");
2409                     }
2410                     sb.append(" cuid=").append(config.creatorUid);
2411                     sb.append(" suid=").append(config.lastUpdateUid);
2412                 }
2413                 break;
2414             case WifiManager.FORGET_NETWORK:
2415                 sb.append(" ");
2416                 sb.append(Integer.toString(msg.arg1));
2417                 sb.append(" ");
2418                 sb.append(Integer.toString(msg.arg2));
2419                 config = (WifiConfiguration) msg.obj;
2420                 if (config != null) {
2421                     sb.append(" ").append(config.configKey());
2422                     sb.append(" nid=").append(config.networkId);
2423                     if (config.hiddenSSID) {
2424                         sb.append(" hidden");
2425                     }
2426                     if (config.preSharedKey != null) {
2427                         sb.append(" hasPSK");
2428                     }
2429                     if (config.ephemeral) {
2430                         sb.append(" ephemeral");
2431                     }
2432                     if (config.selfAdded) {
2433                         sb.append(" selfAdded");
2434                     }
2435                     sb.append(" cuid=").append(config.creatorUid);
2436                     sb.append(" suid=").append(config.lastUpdateUid);
2437                     WifiConfiguration.NetworkSelectionStatus netWorkSelectionStatus =
2438                             config.getNetworkSelectionStatus();
2439                     sb.append(" ajst=").append(
2440                             netWorkSelectionStatus.getNetworkStatusString());
2441                 }
2442                 break;
2443             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2444                 sb.append(" ");
2445                 sb.append(" timedOut=" + Integer.toString(msg.arg1));
2446                 sb.append(" ");
2447                 sb.append(Integer.toString(msg.arg2));
2448                 String bssid = (String) msg.obj;
2449                 if (bssid != null && bssid.length() > 0) {
2450                     sb.append(" ");
2451                     sb.append(bssid);
2452                 }
2453                 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
2454                 break;
2455             case WifiMonitor.SCAN_RESULTS_EVENT:
2456                 sb.append(" ");
2457                 sb.append(Integer.toString(msg.arg1));
2458                 sb.append(" ");
2459                 sb.append(Integer.toString(msg.arg2));
2460                 if (mScanResults != null) {
2461                     sb.append(" found=");
2462                     sb.append(mScanResults.size());
2463                 }
2464                 sb.append(" known=").append(mNumScanResultsKnown);
2465                 sb.append(" got=").append(mNumScanResultsReturned);
2466                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2467                 sb.append(String.format(" con=%d", mConnectionReqCount));
2468                 sb.append(String.format(" untrustedcn=%d", mUntrustedReqCount));
2469                 key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2470                 if (key != null) {
2471                     sb.append(" last=").append(key);
2472                 }
2473                 break;
2474             case WifiMonitor.SCAN_FAILED_EVENT:
2475                 break;
2476             case WifiMonitor.NETWORK_CONNECTION_EVENT:
2477                 sb.append(" ");
2478                 sb.append(Integer.toString(msg.arg1));
2479                 sb.append(" ");
2480                 sb.append(Integer.toString(msg.arg2));
2481                 sb.append(" ").append(mLastBssid);
2482                 sb.append(" nid=").append(mLastNetworkId);
2483                 config = getCurrentWifiConfiguration();
2484                 if (config != null) {
2485                     sb.append(" ").append(config.configKey());
2486                 }
2487                 key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2488                 if (key != null) {
2489                     sb.append(" last=").append(key);
2490                 }
2491                 break;
2492             case CMD_TARGET_BSSID:
2493             case CMD_ASSOCIATED_BSSID:
2494                 sb.append(" ");
2495                 sb.append(Integer.toString(msg.arg1));
2496                 sb.append(" ");
2497                 sb.append(Integer.toString(msg.arg2));
2498                 if (msg.obj != null) {
2499                     sb.append(" BSSID=").append((String) msg.obj);
2500                 }
2501                 if (mTargetRoamBSSID != null) {
2502                     sb.append(" Target=").append(mTargetRoamBSSID);
2503                 }
2504                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2505                 break;
2506             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2507                 if (msg.obj != null) {
2508                     sb.append(" ").append((String) msg.obj);
2509                 }
2510                 sb.append(" nid=").append(msg.arg1);
2511                 sb.append(" reason=").append(msg.arg2);
2512                 if (mLastBssid != null) {
2513                     sb.append(" lastbssid=").append(mLastBssid);
2514                 }
2515                 if (mWifiInfo.getFrequency() != -1) {
2516                     sb.append(" freq=").append(mWifiInfo.getFrequency());
2517                     sb.append(" rssi=").append(mWifiInfo.getRssi());
2518                 }
2519                 if (isLinkDebouncing()) {
2520                     sb.append(" debounce");
2521                 }
2522                 break;
2523             case CMD_RSSI_POLL:
2524             case CMD_UNWANTED_NETWORK:
2525             case WifiManager.RSSI_PKTCNT_FETCH:
2526                 sb.append(" ");
2527                 sb.append(Integer.toString(msg.arg1));
2528                 sb.append(" ");
2529                 sb.append(Integer.toString(msg.arg2));
2530                 if (mWifiInfo.getSSID() != null)
2531                     if (mWifiInfo.getSSID() != null)
2532                         sb.append(" ").append(mWifiInfo.getSSID());
2533                 if (mWifiInfo.getBSSID() != null)
2534                     sb.append(" ").append(mWifiInfo.getBSSID());
2535                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2536                 sb.append(" f=").append(mWifiInfo.getFrequency());
2537                 sb.append(" sc=").append(mWifiInfo.score);
2538                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2539                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2540                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2541                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2542                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2543                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2544                 report = reportOnTime();
2545                 if (report != null) {
2546                     sb.append(" ").append(report);
2547                 }
2548                 if (mWifiScoreReport.isLastReportValid()) {
2549                     sb.append(mWifiScoreReport.getLastReport());
2550                 }
2551                 break;
2552             case CMD_START_CONNECT:
2553             case WifiManager.CONNECT_NETWORK:
2554                 sb.append(" ");
2555                 sb.append(Integer.toString(msg.arg1));
2556                 sb.append(" ");
2557                 sb.append(Integer.toString(msg.arg2));
2558                 config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2559                 if (config != null) {
2560                     sb.append(" ").append(config.configKey());
2561                     if (config.visibility != null) {
2562                         sb.append(" ").append(config.visibility.toString());
2563                     }
2564                 }
2565                 if (mTargetRoamBSSID != null) {
2566                     sb.append(" ").append(mTargetRoamBSSID);
2567                 }
2568                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2569                 config = getCurrentWifiConfiguration();
2570                 if (config != null) {
2571                     sb.append(config.configKey());
2572                     if (config.visibility != null) {
2573                         sb.append(" ").append(config.visibility.toString());
2574                     }
2575                 }
2576                 break;
2577             case CMD_START_ROAM:
2578                 sb.append(" ");
2579                 sb.append(Integer.toString(msg.arg1));
2580                 sb.append(" ");
2581                 sb.append(Integer.toString(msg.arg2));
2582                 ScanResult result = (ScanResult) msg.obj;
2583                 if (result != null) {
2584                     now = mClock.getWallClockMillis();
2585                     sb.append(" bssid=").append(result.BSSID);
2586                     sb.append(" rssi=").append(result.level);
2587                     sb.append(" freq=").append(result.frequency);
2588                     if (result.seen > 0 && result.seen < now) {
2589                         sb.append(" seen=").append(now - result.seen);
2590                     } else {
2591                         // Somehow the timestamp for this scan result is inconsistent
2592                         sb.append(" !seen=").append(result.seen);
2593                     }
2594                 }
2595                 if (mTargetRoamBSSID != null) {
2596                     sb.append(" ").append(mTargetRoamBSSID);
2597                 }
2598                 sb.append(" roam=").append(Boolean.toString(mIsAutoRoaming));
2599                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
2600                 break;
2601             case CMD_ADD_OR_UPDATE_NETWORK:
2602                 sb.append(" ");
2603                 sb.append(Integer.toString(msg.arg1));
2604                 sb.append(" ");
2605                 sb.append(Integer.toString(msg.arg2));
2606                 if (msg.obj != null) {
2607                     config = (WifiConfiguration) msg.obj;
2608                     sb.append(" ").append(config.configKey());
2609                     sb.append(" prio=").append(config.priority);
2610                     sb.append(" status=").append(config.status);
2611                     if (config.BSSID != null) {
2612                         sb.append(" ").append(config.BSSID);
2613                     }
2614                     WifiConfiguration curConfig = getCurrentWifiConfiguration();
2615                     if (curConfig != null) {
2616                         if (curConfig.configKey().equals(config.configKey())) {
2617                             sb.append(" is current");
2618                         } else {
2619                             sb.append(" current=").append(curConfig.configKey());
2620                             sb.append(" prio=").append(curConfig.priority);
2621                             sb.append(" status=").append(curConfig.status);
2622                         }
2623                     }
2624                 }
2625                 break;
2626             case WifiManager.DISABLE_NETWORK:
2627             case CMD_ENABLE_NETWORK:
2628                 sb.append(" ");
2629                 sb.append(Integer.toString(msg.arg1));
2630                 sb.append(" ");
2631                 sb.append(Integer.toString(msg.arg2));
2632                 key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2633                 if (key != null) {
2634                     sb.append(" last=").append(key);
2635                 }
2636                 config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2637                 if (config != null && (key == null || !config.configKey().equals(key))) {
2638                     sb.append(" target=").append(key);
2639                 }
2640                 break;
2641             case CMD_GET_CONFIGURED_NETWORKS:
2642                 sb.append(" ");
2643                 sb.append(Integer.toString(msg.arg1));
2644                 sb.append(" ");
2645                 sb.append(Integer.toString(msg.arg2));
2646                 sb.append(" num=").append(mWifiConfigManager.getConfiguredNetworks().size());
2647                 break;
2648             case DhcpClient.CMD_PRE_DHCP_ACTION:
2649                 sb.append(" ");
2650                 sb.append(Integer.toString(msg.arg1));
2651                 sb.append(" ");
2652                 sb.append(Integer.toString(msg.arg2));
2653                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
2654                 sb.append(",").append(mWifiInfo.txBad);
2655                 sb.append(",").append(mWifiInfo.txRetries);
2656                 break;
2657             case DhcpClient.CMD_POST_DHCP_ACTION:
2658                 sb.append(" ");
2659                 sb.append(Integer.toString(msg.arg1));
2660                 sb.append(" ");
2661                 sb.append(Integer.toString(msg.arg2));
2662                 if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
2663                     sb.append(" OK ");
2664                 } else if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
2665                     sb.append(" FAIL ");
2666                 }
2667                 if (mLinkProperties != null) {
2668                     sb.append(" ");
2669                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2670                 }
2671                 break;
2672             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2673                 sb.append(" ");
2674                 sb.append(Integer.toString(msg.arg1));
2675                 sb.append(" ");
2676                 sb.append(Integer.toString(msg.arg2));
2677                 if (msg.obj != null) {
2678                     NetworkInfo info = (NetworkInfo) msg.obj;
2679                     NetworkInfo.State state = info.getState();
2680                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
2681                     if (state != null) {
2682                         sb.append(" st=").append(state);
2683                     }
2684                     if (detailedState != null) {
2685                         sb.append("/").append(detailedState);
2686                     }
2687                 }
2688                 break;
2689             case CMD_IP_CONFIGURATION_LOST:
2690                 int count = -1;
2691                 WifiConfiguration c = getCurrentWifiConfiguration();
2692                 if (c != null) {
2693                     count = c.getNetworkSelectionStatus().getDisableReasonCounter(
2694                             WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
2695                 }
2696                 sb.append(" ");
2697                 sb.append(Integer.toString(msg.arg1));
2698                 sb.append(" ");
2699                 sb.append(Integer.toString(msg.arg2));
2700                 sb.append(" failures: ");
2701                 sb.append(Integer.toString(count));
2702                 sb.append("/");
2703                 sb.append(Integer.toString(mFacade.getIntegerSetting(
2704                         mContext, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 0)));
2705                 if (mWifiInfo.getBSSID() != null) {
2706                     sb.append(" ").append(mWifiInfo.getBSSID());
2707                 }
2708                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2709                 break;
2710             case CMD_UPDATE_LINKPROPERTIES:
2711                 sb.append(" ");
2712                 sb.append(Integer.toString(msg.arg1));
2713                 sb.append(" ");
2714                 sb.append(Integer.toString(msg.arg2));
2715                 if (mLinkProperties != null) {
2716                     sb.append(" ");
2717                     sb.append(getLinkPropertiesSummary(mLinkProperties));
2718                 }
2719                 break;
2720             case CMD_IP_REACHABILITY_LOST:
2721                 if (msg.obj != null) {
2722                     sb.append(" ").append((String) msg.obj);
2723                 }
2724                 break;
2725             case CMD_INSTALL_PACKET_FILTER:
2726                 sb.append(" len=" + ((byte[])msg.obj).length);
2727                 break;
2728             case CMD_SET_FALLBACK_PACKET_FILTERING:
2729                 sb.append(" enabled=" + (boolean)msg.obj);
2730                 break;
2731             case CMD_ROAM_WATCHDOG_TIMER:
2732                 sb.append(" ");
2733                 sb.append(Integer.toString(msg.arg1));
2734                 sb.append(" ");
2735                 sb.append(Integer.toString(msg.arg2));
2736                 sb.append(" cur=").append(roamWatchdogCount);
2737                 break;
2738             case CMD_DISCONNECTING_WATCHDOG_TIMER:
2739                 sb.append(" ");
2740                 sb.append(Integer.toString(msg.arg1));
2741                 sb.append(" ");
2742                 sb.append(Integer.toString(msg.arg2));
2743                 sb.append(" cur=").append(disconnectingWatchdogCount);
2744                 break;
2745             case CMD_DISABLE_P2P_WATCHDOG_TIMER:
2746                 sb.append(" ");
2747                 sb.append(Integer.toString(msg.arg1));
2748                 sb.append(" ");
2749                 sb.append(Integer.toString(msg.arg2));
2750                 sb.append(" cur=").append(mDisableP2pWatchdogCount);
2751                 break;
2752             case CMD_START_RSSI_MONITORING_OFFLOAD:
2753             case CMD_STOP_RSSI_MONITORING_OFFLOAD:
2754             case CMD_RSSI_THRESHOLD_BREACHED:
2755                 sb.append(" rssi=");
2756                 sb.append(Integer.toString(msg.arg1));
2757                 sb.append(" thresholds=");
2758                 sb.append(Arrays.toString(mRssiRanges));
2759                 break;
2760             case CMD_USER_SWITCH:
2761                 sb.append(" userId=");
2762                 sb.append(Integer.toString(msg.arg1));
2763                 break;
2764             case CMD_IPV4_PROVISIONING_SUCCESS:
2765                 sb.append(" ");
2766                 if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
2767                     sb.append("DHCP_OK");
2768                 } else if (msg.arg1 == CMD_STATIC_IP_SUCCESS) {
2769                     sb.append("STATIC_OK");
2770                 } else {
2771                     sb.append(Integer.toString(msg.arg1));
2772                 }
2773                 break;
2774             case CMD_IPV4_PROVISIONING_FAILURE:
2775                 sb.append(" ");
2776                 if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
2777                     sb.append("DHCP_FAIL");
2778                 } else if (msg.arg1 == CMD_STATIC_IP_FAILURE) {
2779                     sb.append("STATIC_FAIL");
2780                 } else {
2781                     sb.append(Integer.toString(msg.arg1));
2782                 }
2783                 break;
2784             default:
2785                 sb.append(" ");
2786                 sb.append(Integer.toString(msg.arg1));
2787                 sb.append(" ");
2788                 sb.append(Integer.toString(msg.arg2));
2789                 break;
2790         }
2791 
2792         return sb.toString();
2793     }
2794 
handleScreenStateChanged(boolean screenOn)2795     private void handleScreenStateChanged(boolean screenOn) {
2796         mScreenOn = screenOn;
2797         if (mVerboseLoggingEnabled) {
2798             logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
2799                     + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
2800                     + " state " + getCurrentState().getName()
2801                     + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
2802         }
2803         enableRssiPolling(screenOn);
2804         if (mUserWantsSuspendOpt.get()) {
2805             int shouldReleaseWakeLock = 0;
2806             if (screenOn) {
2807                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, shouldReleaseWakeLock);
2808             } else {
2809                 if (isConnected()) {
2810                     // Allow 2s for suspend optimizations to be set
2811                     mSuspendWakeLock.acquire(2000);
2812                     shouldReleaseWakeLock = 1;
2813                 }
2814                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, shouldReleaseWakeLock);
2815             }
2816         }
2817 
2818         getWifiLinkLayerStats();
2819         mOnTimeScreenStateChange = mOnTime;
2820         lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
2821 
2822         mWifiMetrics.setScreenState(screenOn);
2823 
2824         if (mWifiConnectivityManager != null) {
2825             mWifiConnectivityManager.handleScreenStateChanged(screenOn);
2826         }
2827 
2828         if (mVerboseLoggingEnabled) log("handleScreenStateChanged Exit: " + screenOn);
2829     }
2830 
checkAndSetConnectivityInstance()2831     private void checkAndSetConnectivityInstance() {
2832         if (mCm == null) {
2833             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
2834         }
2835     }
2836 
setSuspendOptimizationsNative(int reason, boolean enabled)2837     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
2838         if (mVerboseLoggingEnabled) {
2839             log("setSuspendOptimizationsNative: " + reason + " " + enabled
2840                     + " -want " + mUserWantsSuspendOpt.get()
2841                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2842                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2843                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2844                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2845         }
2846         //mWifiNative.setSuspendOptimizations(enabled);
2847 
2848         if (enabled) {
2849             mSuspendOptNeedsDisabled &= ~reason;
2850             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
2851             if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
2852                 if (mVerboseLoggingEnabled) {
2853                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
2854                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2855                             + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2856                             + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2857                             + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2858                 }
2859                 mWifiNative.setSuspendOptimizations(true);
2860             }
2861         } else {
2862             mSuspendOptNeedsDisabled |= reason;
2863             mWifiNative.setSuspendOptimizations(false);
2864         }
2865     }
2866 
setSuspendOptimizations(int reason, boolean enabled)2867     private void setSuspendOptimizations(int reason, boolean enabled) {
2868         if (mVerboseLoggingEnabled) log("setSuspendOptimizations: " + reason + " " + enabled);
2869         if (enabled) {
2870             mSuspendOptNeedsDisabled &= ~reason;
2871         } else {
2872             mSuspendOptNeedsDisabled |= reason;
2873         }
2874         if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2875     }
2876 
setWifiState(int wifiState)2877     private void setWifiState(int wifiState) {
2878         final int previousWifiState = mWifiState.get();
2879 
2880         try {
2881             if (wifiState == WIFI_STATE_ENABLED) {
2882                 mBatteryStats.noteWifiOn();
2883             } else if (wifiState == WIFI_STATE_DISABLED) {
2884                 mBatteryStats.noteWifiOff();
2885             }
2886         } catch (RemoteException e) {
2887             loge("Failed to note battery stats in wifi");
2888         }
2889 
2890         mWifiState.set(wifiState);
2891 
2892         if (mVerboseLoggingEnabled) log("setWifiState: " + syncGetWifiStateByName());
2893 
2894         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
2895         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2896         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
2897         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
2898         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2899     }
2900 
setWifiApState(int wifiApState, int reason, String ifaceName, int mode)2901     private void setWifiApState(int wifiApState, int reason, String ifaceName, int mode) {
2902         final int previousWifiApState = mWifiApState.get();
2903 
2904         try {
2905             if (wifiApState == WIFI_AP_STATE_ENABLED) {
2906                 mBatteryStats.noteWifiOn();
2907             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
2908                 mBatteryStats.noteWifiOff();
2909             }
2910         } catch (RemoteException e) {
2911             loge("Failed to note battery stats in wifi");
2912         }
2913 
2914         // Update state
2915         mWifiApState.set(wifiApState);
2916 
2917         if (mVerboseLoggingEnabled) log("setWifiApState: " + syncGetWifiApStateByName());
2918 
2919         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
2920         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2921         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
2922         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
2923         if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
2924             //only set reason number when softAP start failed
2925             intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
2926         }
2927 
2928         if (ifaceName == null) {
2929             loge("Updating wifiApState with a null iface name");
2930         }
2931         intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, ifaceName);
2932         intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mode);
2933 
2934         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2935     }
2936 
setScanResults()2937     private void setScanResults() {
2938         mNumScanResultsKnown = 0;
2939         mNumScanResultsReturned = 0;
2940 
2941         ArrayList<ScanDetail> scanResults = mWifiNative.getScanResults();
2942 
2943         if (scanResults.isEmpty()) {
2944             mScanResults = new ArrayList<>();
2945             return;
2946         }
2947 
2948         // TODO(b/31065385): mWifiConfigManager.trimANQPCache(false);
2949 
2950         boolean connected = mLastBssid != null;
2951         long activeBssid = 0L;
2952         if (connected) {
2953             try {
2954                 activeBssid = Utils.parseMac(mLastBssid);
2955             } catch (IllegalArgumentException iae) {
2956                 connected = false;
2957             }
2958         }
2959 
2960         synchronized (mScanResultsLock) {
2961             mScanResults = scanResults;
2962             mNumScanResultsReturned = mScanResults.size();
2963         }
2964 
2965         if (isLinkDebouncing()) {
2966             // If debouncing, we dont re-select a SSID or BSSID hence
2967             // there is no need to call the network selection code
2968             // in WifiAutoJoinController, instead,
2969             // just try to reconnect to the same SSID by triggering a roam
2970             // The third parameter 1 means roam not from network selection but debouncing
2971             sendMessage(CMD_START_ROAM, mLastNetworkId, 1, null);
2972         }
2973     }
2974 
2975     /*
2976      * Fetch RSSI, linkspeed, and frequency on current connection
2977      */
fetchRssiLinkSpeedAndFrequencyNative()2978     private void fetchRssiLinkSpeedAndFrequencyNative() {
2979         Integer newRssi = null;
2980         Integer newLinkSpeed = null;
2981         Integer newFrequency = null;
2982         WifiNative.SignalPollResult pollResult = mWifiNative.signalPoll();
2983         if (pollResult == null) {
2984             return;
2985         }
2986 
2987         newRssi = pollResult.currentRssi;
2988         newLinkSpeed = pollResult.txBitrate;
2989         newFrequency = pollResult.associationFrequency;
2990 
2991         if (mVerboseLoggingEnabled) {
2992             logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" + newRssi +
2993                  " linkspeed=" + newLinkSpeed + " freq=" + newFrequency);
2994         }
2995 
2996         if (newRssi != null && newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
2997             // screen out invalid values
2998             /* some implementations avoid negative values by adding 256
2999              * so we need to adjust for that here.
3000              */
3001             if (newRssi > 0) newRssi -= 256;
3002             mWifiInfo.setRssi(newRssi);
3003             /*
3004              * Rather then sending the raw RSSI out every time it
3005              * changes, we precalculate the signal level that would
3006              * be displayed in the status bar, and only send the
3007              * broadcast if that much more coarse-grained number
3008              * changes. This cuts down greatly on the number of
3009              * broadcasts, at the cost of not informing others
3010              * interested in RSSI of all the changes in signal
3011              * level.
3012              */
3013             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
3014             if (newSignalLevel != mLastSignalLevel) {
3015                 updateCapabilities();
3016                 sendRssiChangeBroadcast(newRssi);
3017             }
3018             mLastSignalLevel = newSignalLevel;
3019         } else {
3020             mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
3021             updateCapabilities();
3022         }
3023 
3024         if (newLinkSpeed != null) {
3025             mWifiInfo.setLinkSpeed(newLinkSpeed);
3026         }
3027         if (newFrequency != null && newFrequency > 0) {
3028             if (ScanResult.is5GHz(newFrequency)) {
3029                 mWifiConnectionStatistics.num5GhzConnected++;
3030             }
3031             if (ScanResult.is24GHz(newFrequency)) {
3032                 mWifiConnectionStatistics.num24GhzConnected++;
3033             }
3034             mWifiInfo.setFrequency(newFrequency);
3035         }
3036         mWifiConfigManager.updateScanDetailCacheFromWifiInfo(mWifiInfo);
3037         /*
3038          * Increment various performance metrics
3039          */
3040         if (newRssi != null && newLinkSpeed != null && newFrequency != null) {
3041             mWifiMetrics.handlePollResult(mWifiInfo);
3042         }
3043     }
3044 
3045     // Polling has completed, hence we wont have a score anymore
cleanWifiScore()3046     private void cleanWifiScore() {
3047         mWifiInfo.txBadRate = 0;
3048         mWifiInfo.txSuccessRate = 0;
3049         mWifiInfo.txRetriesRate = 0;
3050         mWifiInfo.rxSuccessRate = 0;
3051         mWifiScoreReport.reset();
3052     }
3053 
updateLinkProperties(LinkProperties newLp)3054     private void updateLinkProperties(LinkProperties newLp) {
3055         if (mVerboseLoggingEnabled) {
3056             log("Link configuration changed for netId: " + mLastNetworkId
3057                     + " old: " + mLinkProperties + " new: " + newLp);
3058         }
3059         // We own this instance of LinkProperties because IpManager passes us a copy.
3060         mLinkProperties = newLp;
3061         if (mNetworkAgent != null) {
3062             mNetworkAgent.sendLinkProperties(mLinkProperties);
3063         }
3064 
3065         if (getNetworkDetailedState() == DetailedState.CONNECTED) {
3066             // If anything has changed and we're already connected, send out a notification.
3067             // TODO: Update all callers to use NetworkCallbacks and delete this.
3068             sendLinkConfigurationChangedBroadcast();
3069         }
3070 
3071         if (mVerboseLoggingEnabled) {
3072             StringBuilder sb = new StringBuilder();
3073             sb.append("updateLinkProperties nid: " + mLastNetworkId);
3074             sb.append(" state: " + getNetworkDetailedState());
3075 
3076             if (mLinkProperties != null) {
3077                 sb.append(" ");
3078                 sb.append(getLinkPropertiesSummary(mLinkProperties));
3079             }
3080             logd(sb.toString());
3081         }
3082     }
3083 
3084     /**
3085      * Clears all our link properties.
3086      */
clearLinkProperties()3087     private void clearLinkProperties() {
3088         // Clear the link properties obtained from DHCP. The only caller of this
3089         // function has already called IpManager#stop(), which clears its state.
3090         synchronized (mDhcpResultsLock) {
3091             if (mDhcpResults != null) {
3092                 mDhcpResults.clear();
3093             }
3094         }
3095 
3096         // Now clear the merged link properties.
3097         mLinkProperties.clear();
3098         if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
3099     }
3100 
3101     /**
3102      * try to update default route MAC address.
3103      */
updateDefaultRouteMacAddress(int timeout)3104     private String updateDefaultRouteMacAddress(int timeout) {
3105         String address = null;
3106         for (RouteInfo route : mLinkProperties.getRoutes()) {
3107             if (route.isDefaultRoute() && route.hasGateway()) {
3108                 InetAddress gateway = route.getGateway();
3109                 if (gateway instanceof Inet4Address) {
3110                     if (mVerboseLoggingEnabled) {
3111                         logd("updateDefaultRouteMacAddress found Ipv4 default :"
3112                                 + gateway.getHostAddress());
3113                     }
3114                     address = macAddressFromRoute(gateway.getHostAddress());
3115                     /* The gateway's MAC address is known */
3116                     if ((address == null) && (timeout > 0)) {
3117                         boolean reachable = false;
3118                         TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
3119                         try {
3120                             reachable = gateway.isReachable(timeout);
3121                         } catch (Exception e) {
3122                             loge("updateDefaultRouteMacAddress exception reaching :"
3123                                     + gateway.getHostAddress());
3124 
3125                         } finally {
3126                             TrafficStats.clearThreadStatsTag();
3127                             if (reachable == true) {
3128 
3129                                 address = macAddressFromRoute(gateway.getHostAddress());
3130                                 if (mVerboseLoggingEnabled) {
3131                                     logd("updateDefaultRouteMacAddress reachable (tried again) :"
3132                                             + gateway.getHostAddress() + " found " + address);
3133                                 }
3134                             }
3135                         }
3136                     }
3137                     if (address != null) {
3138                         mWifiConfigManager.setNetworkDefaultGwMacAddress(mLastNetworkId, address);
3139                     }
3140                 }
3141             }
3142         }
3143         return address;
3144     }
3145 
sendRssiChangeBroadcast(final int newRssi)3146     private void sendRssiChangeBroadcast(final int newRssi) {
3147         try {
3148             mBatteryStats.noteWifiRssiChanged(newRssi);
3149         } catch (RemoteException e) {
3150             // Won't happen.
3151         }
3152         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
3153         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3154         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
3155         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3156     }
3157 
sendNetworkStateChangeBroadcast(String bssid)3158     private void sendNetworkStateChangeBroadcast(String bssid) {
3159         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
3160         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3161         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
3162         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
3163         if (bssid != null)
3164             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
3165         if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
3166                 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
3167             // We no longer report MAC address to third-parties and our code does
3168             // not rely on this broadcast, so just send the default MAC address.
3169             fetchRssiLinkSpeedAndFrequencyNative();
3170             WifiInfo sentWifiInfo = new WifiInfo(mWifiInfo);
3171             sentWifiInfo.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
3172             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, sentWifiInfo);
3173         }
3174         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3175     }
3176 
sendLinkConfigurationChangedBroadcast()3177     private void sendLinkConfigurationChangedBroadcast() {
3178         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
3179         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3180         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
3181         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
3182     }
3183 
sendSupplicantConnectionChangedBroadcast(boolean connected)3184     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
3185         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
3186         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3187         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
3188         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
3189     }
3190 
3191     /**
3192      * Record the detailed state of a network.
3193      *
3194      * @param state the new {@code DetailedState}
3195      */
setNetworkDetailedState(NetworkInfo.DetailedState state)3196     private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
3197         boolean hidden = false;
3198 
3199         if (isLinkDebouncing() || mIsAutoRoaming) {
3200             // There is generally a confusion in the system about colluding
3201             // WiFi Layer 2 state (as reported by supplicant) and the Network state
3202             // which leads to multiple confusion.
3203             //
3204             // If link is de-bouncing or roaming, we already have an IP address
3205             // as well we were connected and are doing L2 cycles of
3206             // reconnecting or renewing IP address to check that we still have it
3207             // This L2 link flapping should ne be reflected into the Network state
3208             // which is the state of the WiFi Network visible to Layer 3 and applications
3209             // Note that once debouncing and roaming are completed, we will
3210             // set the Network state to where it should be, or leave it as unchanged
3211             //
3212             hidden = true;
3213         }
3214         if (mVerboseLoggingEnabled) {
3215             log("setDetailed state, old ="
3216                     + mNetworkInfo.getDetailedState() + " and new state=" + state
3217                     + " hidden=" + hidden);
3218         }
3219         if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null
3220                 && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
3221             // Always indicate that SSID has changed
3222             if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
3223                 if (mVerboseLoggingEnabled) {
3224                     log("setDetailed state send new extra info" + mWifiInfo.getSSID());
3225                 }
3226                 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
3227                 sendNetworkStateChangeBroadcast(null);
3228             }
3229         }
3230         if (hidden == true) {
3231             return false;
3232         }
3233 
3234         if (state != mNetworkInfo.getDetailedState()) {
3235             mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
3236             if (mNetworkAgent != null) {
3237                 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
3238             }
3239             sendNetworkStateChangeBroadcast(null);
3240             return true;
3241         }
3242         return false;
3243     }
3244 
getNetworkDetailedState()3245     private DetailedState getNetworkDetailedState() {
3246         return mNetworkInfo.getDetailedState();
3247     }
3248 
handleSupplicantStateChange(Message message)3249     private SupplicantState handleSupplicantStateChange(Message message) {
3250         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3251         SupplicantState state = stateChangeResult.state;
3252         // Supplicant state change
3253         // [31-13] Reserved for future use
3254         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
3255         // 50023 supplicant_state_changed (custom|1|5)
3256         mWifiInfo.setSupplicantState(state);
3257         // If we receive a supplicant state change with an empty SSID,
3258         // this implies that wpa_supplicant is already disconnected.
3259         // We should pretend we are still connected when linkDebouncing is on.
3260         if ((stateChangeResult.wifiSsid == null
3261                 || stateChangeResult.wifiSsid.toString().isEmpty()) && isLinkDebouncing()) {
3262             return state;
3263         }
3264         // Network id is only valid when we start connecting
3265         if (SupplicantState.isConnecting(state)) {
3266             mWifiInfo.setNetworkId(lookupFrameworkNetworkId(stateChangeResult.networkId));
3267         } else {
3268             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
3269         }
3270 
3271         mWifiInfo.setBSSID(stateChangeResult.BSSID);
3272         mWifiInfo.setSSID(stateChangeResult.wifiSsid);
3273 
3274         final WifiConfiguration config = getCurrentWifiConfiguration();
3275         if (config != null) {
3276             mWifiInfo.setEphemeral(config.ephemeral);
3277 
3278             // Set meteredHint if scan result says network is expensive
3279             ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCacheForNetwork(
3280                     config.networkId);
3281             if (scanDetailCache != null) {
3282                 ScanDetail scanDetail = scanDetailCache.getScanDetail(stateChangeResult.BSSID);
3283                 if (scanDetail != null) {
3284                     mWifiInfo.setFrequency(scanDetail.getScanResult().frequency);
3285                     NetworkDetail networkDetail = scanDetail.getNetworkDetail();
3286                     if (networkDetail != null
3287                             && networkDetail.getAnt() == NetworkDetail.Ant.ChargeablePublic) {
3288                         mWifiInfo.setMeteredHint(true);
3289                     }
3290                 }
3291             }
3292         }
3293 
3294         mSupplicantStateTracker.sendMessage(Message.obtain(message));
3295         return state;
3296     }
3297 
3298     /**
3299      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
3300      * using the interface, stopping DHCP & disabling interface
3301      */
handleNetworkDisconnect()3302     private void handleNetworkDisconnect() {
3303         if (mVerboseLoggingEnabled) {
3304             log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
3305                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3306                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3307                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3308                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3309         }
3310 
3311         stopRssiMonitoringOffload();
3312 
3313         clearTargetBssid("handleNetworkDisconnect");
3314 
3315         stopIpManager();
3316 
3317         /* Reset data structures */
3318         mWifiScoreReport.reset();
3319         mWifiInfo.reset();
3320         mIsLinkDebouncing = false;
3321         /* Reset roaming parameters */
3322         mIsAutoRoaming = false;
3323 
3324         setNetworkDetailedState(DetailedState.DISCONNECTED);
3325         if (mNetworkAgent != null) {
3326             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
3327             mNetworkAgent = null;
3328         }
3329 
3330         /* Clear network properties */
3331         clearLinkProperties();
3332 
3333         /* Cend event to CM & network change broadcast */
3334         sendNetworkStateChangeBroadcast(mLastBssid);
3335 
3336         mLastBssid = null;
3337         registerDisconnected();
3338         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
3339     }
3340 
handleSupplicantConnectionLoss(boolean killSupplicant)3341     private void handleSupplicantConnectionLoss(boolean killSupplicant) {
3342         /* Socket connection can be lost when we do a graceful shutdown
3343         * or when the driver is hung. Ensure supplicant is stopped here.
3344         */
3345         if (killSupplicant) {
3346             mWifiMonitor.stopAllMonitoring();
3347             if (!mWifiNative.disableSupplicant()) {
3348                 loge("Failed to disable supplicant after connection loss");
3349             }
3350         }
3351         mWifiNative.closeSupplicantConnection();
3352         sendSupplicantConnectionChangedBroadcast(false);
3353         setWifiState(WIFI_STATE_DISABLED);
3354     }
3355 
handlePreDhcpSetup()3356     void handlePreDhcpSetup() {
3357         if (!mBluetoothConnectionActive) {
3358             /*
3359              * There are problems setting the Wi-Fi driver's power
3360              * mode to active when bluetooth coexistence mode is
3361              * enabled or sense.
3362              * <p>
3363              * We set Wi-Fi to active mode when
3364              * obtaining an IP address because we've found
3365              * compatibility issues with some routers with low power
3366              * mode.
3367              * <p>
3368              * In order for this active power mode to properly be set,
3369              * we disable coexistence mode until we're done with
3370              * obtaining an IP address.  One exception is if we
3371              * are currently connected to a headset, since disabling
3372              * coexistence would interrupt that connection.
3373              */
3374             // Disable the coexistence mode
3375             mWifiNative.setBluetoothCoexistenceMode(
3376                     WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
3377         }
3378 
3379         // Disable power save and suspend optimizations during DHCP
3380         // Note: The order here is important for now. Brcm driver changes
3381         // power settings when we control suspend mode optimizations.
3382         // TODO: Remove this comment when the driver is fixed.
3383         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
3384         mWifiNative.setPowerSave(false);
3385 
3386         // Update link layer stats
3387         getWifiLinkLayerStats();
3388 
3389         if (mWifiP2pChannel != null) {
3390             /* P2p discovery breaks dhcp, shut it down in order to get through this */
3391             Message msg = new Message();
3392             msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
3393             msg.arg1 = WifiP2pServiceImpl.ENABLED;
3394             msg.arg2 = DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE;
3395             msg.obj = WifiStateMachine.this;
3396             mWifiP2pChannel.sendMessage(msg);
3397         } else {
3398             // If the p2p service is not running, we can proceed directly.
3399             sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
3400         }
3401     }
3402 
handlePostDhcpSetup()3403     void handlePostDhcpSetup() {
3404         /* Restore power save and suspend optimizations */
3405         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
3406         mWifiNative.setPowerSave(true);
3407 
3408         p2pSendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
3409 
3410         // Set the coexistence mode back to its default value
3411         mWifiNative.setBluetoothCoexistenceMode(
3412                 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
3413     }
3414 
3415     private static final long DIAGS_CONNECT_TIMEOUT_MILLIS = 60 * 1000;
3416     private long mDiagsConnectionStartMillis = -1;
3417     /**
3418      * Inform other components that a new connection attempt is starting.
3419      */
reportConnectionAttemptStart( WifiConfiguration config, String targetBSSID, int roamType)3420     private void reportConnectionAttemptStart(
3421             WifiConfiguration config, String targetBSSID, int roamType) {
3422         mWifiMetrics.startConnectionEvent(config, targetBSSID, roamType);
3423         mDiagsConnectionStartMillis = mClock.getElapsedSinceBootMillis();
3424         mWifiDiagnostics.reportConnectionEvent(
3425                 mDiagsConnectionStartMillis, WifiDiagnostics.CONNECTION_EVENT_STARTED);
3426         mWrongPasswordNotifier.onNewConnectionAttempt();
3427         // TODO(b/35329124): Remove CMD_DIAGS_CONNECT_TIMEOUT, once WifiStateMachine
3428         // grows a proper CONNECTING state.
3429         sendMessageDelayed(CMD_DIAGS_CONNECT_TIMEOUT,
3430                 mDiagsConnectionStartMillis, DIAGS_CONNECT_TIMEOUT_MILLIS);
3431     }
3432 
3433     /**
3434      * Inform other components (WifiMetrics, WifiDiagnostics, WifiConnectivityManager, etc.) that
3435      * the current connection attempt has concluded.
3436      */
reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode)3437     private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode) {
3438         mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode);
3439         mWifiConnectivityManager.handleConnectionAttemptEnded(level2FailureCode);
3440         switch (level2FailureCode) {
3441             case WifiMetrics.ConnectionEvent.FAILURE_NONE:
3442                 // Ideally, we'd wait until IP reachability has been confirmed. this code falls
3443                 // short in two ways:
3444                 // - at the time of the CMD_IP_CONFIGURATION_SUCCESSFUL event, we don't know if we
3445                 //   actually have ARP reachability. it might be better to wait until the wifi
3446                 //   network has been validated by IpManager.
3447                 // - in the case of a roaming event (intra-SSID), we probably trigger when L2 is
3448                 //   complete.
3449                 //
3450                 // TODO(b/34181219): Fix the above.
3451                 mWifiDiagnostics.reportConnectionEvent(
3452                         mDiagsConnectionStartMillis, WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED);
3453                 break;
3454             case WifiMetrics.ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
3455             case WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED:
3456                 // WifiDiagnostics doesn't care about pre-empted connections, or cases
3457                 // where we failed to initiate a connection attempt with supplicant.
3458                 break;
3459             default:
3460                 mWifiDiagnostics.reportConnectionEvent(
3461                         mDiagsConnectionStartMillis, WifiDiagnostics.CONNECTION_EVENT_FAILED);
3462         }
3463         mDiagsConnectionStartMillis = -1;
3464     }
3465 
handleIPv4Success(DhcpResults dhcpResults)3466     private void handleIPv4Success(DhcpResults dhcpResults) {
3467         if (mVerboseLoggingEnabled) {
3468             logd("handleIPv4Success <" + dhcpResults.toString() + ">");
3469             logd("link address " + dhcpResults.ipAddress);
3470         }
3471 
3472         Inet4Address addr;
3473         synchronized (mDhcpResultsLock) {
3474             mDhcpResults = dhcpResults;
3475             addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
3476         }
3477 
3478         if (mIsAutoRoaming) {
3479             int previousAddress = mWifiInfo.getIpAddress();
3480             int newAddress = NetworkUtils.inetAddressToInt(addr);
3481             if (previousAddress != newAddress) {
3482                 logd("handleIPv4Success, roaming and address changed" +
3483                         mWifiInfo + " got: " + addr);
3484             }
3485         }
3486 
3487         mWifiInfo.setInetAddress(addr);
3488 
3489         final WifiConfiguration config = getCurrentWifiConfiguration();
3490         if (config != null) {
3491             mWifiInfo.setEphemeral(config.ephemeral);
3492         }
3493 
3494         // Set meteredHint if DHCP result says network is metered
3495         if (dhcpResults.hasMeteredHint()) {
3496             mWifiInfo.setMeteredHint(true);
3497         }
3498 
3499         updateCapabilities(config);
3500     }
3501 
handleSuccessfulIpConfiguration()3502     private void handleSuccessfulIpConfiguration() {
3503         mLastSignalLevel = -1; // Force update of signal strength
3504         WifiConfiguration c = getCurrentWifiConfiguration();
3505         if (c != null) {
3506             // Reset IP failure tracking
3507             c.getNetworkSelectionStatus().clearDisableReasonCounter(
3508                     WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3509 
3510             // Tell the framework whether the newly connected network is trusted or untrusted.
3511             updateCapabilities(c);
3512         }
3513         if (c != null) {
3514             ScanResult result = getCurrentScanResult();
3515             if (result == null) {
3516                 logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
3517                         c.configKey());
3518             } else {
3519                 // Clear the per BSSID failure count
3520                 result.numIpConfigFailures = 0;
3521             }
3522         }
3523     }
3524 
handleIPv4Failure()3525     private void handleIPv4Failure() {
3526         // TODO: Move this to provisioning failure, not DHCP failure.
3527         // DHCPv4 failure is expected on an IPv6-only network.
3528         mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_DHCP_FAILURE);
3529         if (mVerboseLoggingEnabled) {
3530             int count = -1;
3531             WifiConfiguration config = getCurrentWifiConfiguration();
3532             if (config != null) {
3533                 count = config.getNetworkSelectionStatus().getDisableReasonCounter(
3534                         WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3535             }
3536             log("DHCP failure count=" + count);
3537         }
3538         reportConnectionAttemptEnd(
3539                 WifiMetrics.ConnectionEvent.FAILURE_DHCP,
3540                 WifiMetricsProto.ConnectionEvent.HLF_DHCP);
3541         synchronized(mDhcpResultsLock) {
3542              if (mDhcpResults != null) {
3543                  mDhcpResults.clear();
3544              }
3545         }
3546         if (mVerboseLoggingEnabled) {
3547             logd("handleIPv4Failure");
3548         }
3549     }
3550 
handleIpConfigurationLost()3551     private void handleIpConfigurationLost() {
3552         mWifiInfo.setInetAddress(null);
3553         mWifiInfo.setMeteredHint(false);
3554 
3555         mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
3556                 WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3557 
3558         /* DHCP times out after about 30 seconds, we do a
3559          * disconnect thru supplicant, we will let autojoin retry connecting to the network
3560          */
3561         mWifiNative.disconnect();
3562     }
3563 
3564     // TODO: De-duplicated this and handleIpConfigurationLost().
handleIpReachabilityLost()3565     private void handleIpReachabilityLost() {
3566         mWifiInfo.setInetAddress(null);
3567         mWifiInfo.setMeteredHint(false);
3568 
3569         // TODO: Determine whether to call some form of mWifiConfigManager.handleSSIDStateChange().
3570 
3571         // Disconnect via supplicant, and let autojoin retry connecting to the network.
3572         mWifiNative.disconnect();
3573     }
3574 
3575     /*
3576      * Read a MAC address in /proc/arp/table, used by WifistateMachine
3577      * so as to record MAC address of default gateway.
3578      **/
macAddressFromRoute(String ipAddress)3579     private String macAddressFromRoute(String ipAddress) {
3580         String macAddress = null;
3581         BufferedReader reader = null;
3582         try {
3583             reader = new BufferedReader(new FileReader("/proc/net/arp"));
3584 
3585             // Skip over the line bearing colum titles
3586             String line = reader.readLine();
3587 
3588             while ((line = reader.readLine()) != null) {
3589                 String[] tokens = line.split("[ ]+");
3590                 if (tokens.length < 6) {
3591                     continue;
3592                 }
3593 
3594                 // ARP column format is
3595                 // Address HWType HWAddress Flags Mask IFace
3596                 String ip = tokens[0];
3597                 String mac = tokens[3];
3598 
3599                 if (ipAddress.equals(ip)) {
3600                     macAddress = mac;
3601                     break;
3602                 }
3603             }
3604 
3605             if (macAddress == null) {
3606                 loge("Did not find remoteAddress {" + ipAddress + "} in " +
3607                         "/proc/net/arp");
3608             }
3609 
3610         } catch (FileNotFoundException e) {
3611             loge("Could not open /proc/net/arp to lookup mac address");
3612         } catch (IOException e) {
3613             loge("Could not read /proc/net/arp to lookup mac address");
3614         } finally {
3615             try {
3616                 if (reader != null) {
3617                     reader.close();
3618                 }
3619             } catch (IOException e) {
3620                 // Do nothing
3621             }
3622         }
3623         return macAddress;
3624 
3625     }
3626 
3627     /**
3628      * Determine if the specified auth failure is considered to be a permanent wrong password
3629      * failure. The criteria for such failure is when wrong password error is detected
3630      * and the network had never been connected before.
3631      *
3632      * For networks that have previously connected successfully, we consider wrong password
3633      * failures to be temporary, to be on the conservative side.  Since this might be the
3634      * case where we are trying to connect to a wrong network (e.g. A network with same SSID
3635      * but different password).
3636      */
isPermanentWrongPasswordFailure(int networkId, int reasonCode)3637     private boolean isPermanentWrongPasswordFailure(int networkId, int reasonCode) {
3638         if (reasonCode != WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD) {
3639             return false;
3640         }
3641         WifiConfiguration network = mWifiConfigManager.getConfiguredNetwork(networkId);
3642         if (network != null && network.getNetworkSelectionStatus().getHasEverConnected()) {
3643             return false;
3644         }
3645         return true;
3646     }
3647 
3648     private class WifiNetworkFactory extends NetworkFactory {
WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f)3649         public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
3650             super(l, c, TAG, f);
3651         }
3652 
3653         @Override
needNetworkFor(NetworkRequest networkRequest, int score)3654         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
3655             synchronized (mWifiReqCountLock) {
3656                 if (++mConnectionReqCount == 1) {
3657                     if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
3658                         mWifiConnectivityManager.enable(true);
3659                     }
3660                 }
3661             }
3662         }
3663 
3664         @Override
releaseNetworkFor(NetworkRequest networkRequest)3665         protected void releaseNetworkFor(NetworkRequest networkRequest) {
3666             synchronized (mWifiReqCountLock) {
3667                 if (--mConnectionReqCount == 0) {
3668                     if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
3669                         mWifiConnectivityManager.enable(false);
3670                     }
3671                 }
3672             }
3673         }
3674 
3675         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3676         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3677             pw.println("mConnectionReqCount " + mConnectionReqCount);
3678         }
3679 
3680     }
3681 
3682     private class UntrustedWifiNetworkFactory extends NetworkFactory {
UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f)3683         public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
3684             super(l, c, tag, f);
3685         }
3686 
3687         @Override
needNetworkFor(NetworkRequest networkRequest, int score)3688         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
3689             if (!networkRequest.networkCapabilities.hasCapability(
3690                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
3691                 synchronized (mWifiReqCountLock) {
3692                     if (++mUntrustedReqCount == 1) {
3693                         if (mWifiConnectivityManager != null) {
3694                             if (mConnectionReqCount == 0) {
3695                                 mWifiConnectivityManager.enable(true);
3696                             }
3697                             mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
3698                         }
3699                     }
3700                 }
3701             }
3702         }
3703 
3704         @Override
releaseNetworkFor(NetworkRequest networkRequest)3705         protected void releaseNetworkFor(NetworkRequest networkRequest) {
3706             if (!networkRequest.networkCapabilities.hasCapability(
3707                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
3708                 synchronized (mWifiReqCountLock) {
3709                     if (--mUntrustedReqCount == 0) {
3710                         if (mWifiConnectivityManager != null) {
3711                             mWifiConnectivityManager.setUntrustedConnectionAllowed(false);
3712                             if (mConnectionReqCount == 0) {
3713                                 mWifiConnectivityManager.enable(false);
3714                             }
3715                         }
3716                     }
3717                 }
3718             }
3719         }
3720 
3721         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3722         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3723             pw.println("mUntrustedReqCount " + mUntrustedReqCount);
3724         }
3725     }
3726 
maybeRegisterNetworkFactory()3727     void maybeRegisterNetworkFactory() {
3728         if (mNetworkFactory == null) {
3729             checkAndSetConnectivityInstance();
3730             if (mCm != null) {
3731                 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
3732                         NETWORKTYPE, mNetworkCapabilitiesFilter);
3733                 mNetworkFactory.setScoreFilter(60);
3734                 mNetworkFactory.register();
3735 
3736                 // We can't filter untrusted network in the capabilities filter because a trusted
3737                 // network would still satisfy a request that accepts untrusted ones.
3738                 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(),
3739                         mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter);
3740                 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE);
3741                 mUntrustedNetworkFactory.register();
3742             }
3743         }
3744     }
3745 
3746     /**
3747      * WifiStateMachine needs to enable/disable other services when wifi is in client mode.  This
3748      * method allows WifiStateMachine to get these additional system services.
3749      *
3750      * At this time, this method is used to setup variables for P2P service and Wifi Aware.
3751      */
getAdditionalWifiServiceInterfaces()3752     private void getAdditionalWifiServiceInterfaces() {
3753         // First set up Wifi Direct
3754         if (mP2pSupported) {
3755             IBinder s1 = mFacade.getService(Context.WIFI_P2P_SERVICE);
3756             WifiP2pServiceImpl wifiP2pServiceImpl =
3757                     (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1);
3758 
3759             if (wifiP2pServiceImpl != null) {
3760                 mWifiP2pChannel = new AsyncChannel();
3761                 mWifiP2pChannel.connect(mContext, getHandler(),
3762                         wifiP2pServiceImpl.getP2pStateMachineMessenger());
3763             }
3764         }
3765     }
3766 
3767     /**
3768      * Helper function to increment the appropriate setup failure metrics.
3769      */
incrementMetricsForSetupFailure(int failureReason)3770     private void incrementMetricsForSetupFailure(int failureReason) {
3771         if (failureReason == WifiNative.SETUP_FAILURE_HAL) {
3772             mWifiMetrics.incrementNumWifiOnFailureDueToHal();
3773         } else if (failureReason == WifiNative.SETUP_FAILURE_WIFICOND) {
3774             mWifiMetrics.incrementNumWifiOnFailureDueToWificond();
3775         }
3776     }
3777 
3778     /**
3779      * Register the phone listener if we need to set/reset the power limits during voice call for
3780      * this device.
3781      */
maybeRegisterPhoneListener()3782     private void maybeRegisterPhoneListener() {
3783         if (mEnableVoiceCallSarTxPowerLimit) {
3784             logd("Registering for telephony call state changes");
3785             getTelephonyManager().listen(
3786                     mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
3787         }
3788     }
3789 
3790     /**
3791      * Listen for phone call state events to set/reset TX power limits for SAR requirements.
3792      */
3793     private class WifiPhoneStateListener extends PhoneStateListener {
WifiPhoneStateListener(Looper looper)3794         WifiPhoneStateListener(Looper looper) {
3795             super(looper);
3796         }
3797 
3798         @Override
onCallStateChanged(int state, String incomingNumber)3799         public void onCallStateChanged(int state, String incomingNumber) {
3800             if (mEnableVoiceCallSarTxPowerLimit) {
3801                 if (state == CALL_STATE_OFFHOOK) {
3802                     sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
3803                             WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
3804                 } else if (state == CALL_STATE_IDLE) {
3805                     sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
3806                             WifiNative.TX_POWER_SCENARIO_NORMAL);
3807                 }
3808             }
3809         }
3810     }
3811 
3812     /********************************************************
3813      * HSM states
3814      *******************************************************/
3815 
3816     class DefaultState extends State {
3817 
3818         @Override
processMessage(Message message)3819         public boolean processMessage(Message message) {
3820             logStateAndMessage(message, this);
3821 
3822             switch (message.what) {
3823                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
3824                     AsyncChannel ac = (AsyncChannel) message.obj;
3825                     if (ac == mWifiP2pChannel) {
3826                         if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3827                             p2pSendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3828                             // since the p2p channel is connected, we should enable p2p if we are in
3829                             // connect mode.  We may not be in connect mode yet, we may have just
3830                             // set the operational mode and started to set up for connect mode.
3831                             if (mOperationalMode == CONNECT_MODE) {
3832                                 // This message will only be handled if we are in Connect mode.
3833                                 // If we are not in connect mode yet, this will be dropped and the
3834                                 // ConnectMode.enter method will call to enable p2p.
3835                                 sendMessage(CMD_ENABLE_P2P);
3836                             }
3837                         } else {
3838                             // TODO: We should probably do some cleanup or attempt a retry
3839                             // b/34283611
3840                             loge("WifiP2pService connection failure, error=" + message.arg1);
3841                         }
3842                     } else {
3843                         loge("got HALF_CONNECTED for unknown channel");
3844                     }
3845                     break;
3846                 }
3847                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
3848                     AsyncChannel ac = (AsyncChannel) message.obj;
3849                     if (ac == mWifiP2pChannel) {
3850                         loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
3851                         //TODO: Re-establish connection to state machine after a delay (b/34283611)
3852                         // mWifiP2pChannel.connect(mContext, getHandler(),
3853                         // mWifiP2pManager.getMessenger());
3854                     }
3855                     break;
3856                 }
3857                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
3858                     mBluetoothConnectionActive = (message.arg1 !=
3859                             BluetoothAdapter.STATE_DISCONNECTED);
3860                     break;
3861                 case CMD_ENABLE_NETWORK:
3862                     boolean disableOthers = message.arg2 == 1;
3863                     int netId = message.arg1;
3864                     boolean ok = mWifiConfigManager.enableNetwork(
3865                             netId, disableOthers, message.sendingUid);
3866                     if (!ok) {
3867                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
3868                     }
3869                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
3870                     break;
3871                 case CMD_ADD_OR_UPDATE_NETWORK:
3872                     WifiConfiguration config = (WifiConfiguration) message.obj;
3873                     NetworkUpdateResult result =
3874                             mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
3875                     if (!result.isSuccess()) {
3876                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
3877                     }
3878                     replyToMessage(message, message.what, result.getNetworkId());
3879                     break;
3880                 case CMD_SAVE_CONFIG:
3881                     replyToMessage(message, message.what, FAILURE);
3882                     break;
3883                 case CMD_REMOVE_NETWORK:
3884                     deleteNetworkConfigAndSendReply(message, false);
3885                     break;
3886                 case CMD_GET_CONFIGURED_NETWORKS:
3887                     replyToMessage(message, message.what, mWifiConfigManager.getSavedNetworks());
3888                     break;
3889                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
3890                     replyToMessage(message, message.what,
3891                             mWifiConfigManager.getConfiguredNetworksWithPasswords());
3892                     break;
3893                 case CMD_ENABLE_RSSI_POLL:
3894                     mEnableRssiPolling = (message.arg1 == 1);
3895                     break;
3896                 case CMD_SET_HIGH_PERF_MODE:
3897                     if (message.arg1 == 1) {
3898                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
3899                     } else {
3900                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
3901                     }
3902                     break;
3903                 case CMD_INITIALIZE:
3904                     ok = mWifiNative.initializeVendorHal(mVendorHalDeathRecipient);
3905                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
3906                     break;
3907                 case CMD_BOOT_COMPLETED:
3908                     // get other services that we need to manage
3909                     getAdditionalWifiServiceInterfaces();
3910                     if (!mWifiConfigManager.loadFromStore()) {
3911                         Log.e(TAG, "Failed to load from config store");
3912                     }
3913                     maybeRegisterNetworkFactory();
3914                     maybeRegisterPhoneListener();
3915                     break;
3916                 case CMD_SCREEN_STATE_CHANGED:
3917                     handleScreenStateChanged(message.arg1 != 0);
3918                     break;
3919                     /* Discard */
3920                 case CMD_START_SCAN:
3921                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3922                     break;
3923                 case CMD_START_SUPPLICANT:
3924                 case CMD_STOP_SUPPLICANT:
3925                 case CMD_DRIVER_START_TIMED_OUT:
3926                 case CMD_START_AP:
3927                 case CMD_START_AP_FAILURE:
3928                 case CMD_STOP_AP:
3929                 case CMD_AP_STOPPED:
3930                 case CMD_DISCONNECT:
3931                 case CMD_RECONNECT:
3932                 case CMD_REASSOCIATE:
3933                 case CMD_RELOAD_TLS_AND_RECONNECT:
3934                 case WifiMonitor.SUP_CONNECTION_EVENT:
3935                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
3936                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3937                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3938                 case WifiMonitor.SCAN_RESULTS_EVENT:
3939                 case WifiMonitor.SCAN_FAILED_EVENT:
3940                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3941                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3942                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3943                 case WifiMonitor.WPS_OVERLAP_EVENT:
3944                 case CMD_SET_OPERATIONAL_MODE:
3945                 case CMD_RSSI_POLL:
3946                 case DhcpClient.CMD_PRE_DHCP_ACTION:
3947                 case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
3948                 case DhcpClient.CMD_POST_DHCP_ACTION:
3949                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
3950                 case CMD_ENABLE_P2P:
3951                 case CMD_DISABLE_P2P_RSP:
3952                 case WifiMonitor.SUP_REQUEST_IDENTITY:
3953                 case CMD_TEST_NETWORK_DISCONNECT:
3954                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
3955                 case CMD_TARGET_BSSID:
3956                 case CMD_START_CONNECT:
3957                 case CMD_START_ROAM:
3958                 case CMD_ASSOCIATED_BSSID:
3959                 case CMD_UNWANTED_NETWORK:
3960                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
3961                 case CMD_ROAM_WATCHDOG_TIMER:
3962                 case CMD_DISABLE_P2P_WATCHDOG_TIMER:
3963                 case CMD_DISABLE_EPHEMERAL_NETWORK:
3964                 case CMD_SELECT_TX_POWER_SCENARIO:
3965                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3966                     break;
3967                 case CMD_SET_SUSPEND_OPT_ENABLED:
3968                     if (message.arg1 == 1) {
3969                         if (message.arg2 == 1) {
3970                             mSuspendWakeLock.release();
3971                         }
3972                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
3973                     } else {
3974                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
3975                     }
3976                     break;
3977                 case WifiManager.CONNECT_NETWORK:
3978                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
3979                             WifiManager.BUSY);
3980                     break;
3981                 case WifiManager.FORGET_NETWORK:
3982                     deleteNetworkConfigAndSendReply(message, true);
3983                     break;
3984                 case WifiManager.SAVE_NETWORK:
3985                     saveNetworkConfigAndSendReply(message);
3986                     break;
3987                 case WifiManager.START_WPS:
3988                     replyToMessage(message, WifiManager.WPS_FAILED,
3989                             WifiManager.BUSY);
3990                     break;
3991                 case WifiManager.CANCEL_WPS:
3992                     replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
3993                             WifiManager.BUSY);
3994                     break;
3995                 case WifiManager.DISABLE_NETWORK:
3996                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
3997                             WifiManager.BUSY);
3998                     break;
3999                 case WifiManager.RSSI_PKTCNT_FETCH:
4000                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
4001                             WifiManager.BUSY);
4002                     break;
4003                 case CMD_GET_SUPPORTED_FEATURES:
4004                     int featureSet = mWifiNative.getSupportedFeatureSet();
4005                     replyToMessage(message, message.what, featureSet);
4006                     break;
4007                 case CMD_FIRMWARE_ALERT:
4008                     if (mWifiDiagnostics != null) {
4009                         byte[] buffer = (byte[])message.obj;
4010                         int alertReason = message.arg1;
4011                         mWifiDiagnostics.captureAlertData(alertReason, buffer);
4012                         mWifiMetrics.incrementAlertReasonCount(alertReason);
4013                     }
4014                     break;
4015                 case CMD_GET_LINK_LAYER_STATS:
4016                     // Not supported hence reply with error message
4017                     replyToMessage(message, message.what, null);
4018                     break;
4019                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
4020                     NetworkInfo info = (NetworkInfo) message.obj;
4021                     mP2pConnected.set(info.isConnected());
4022                     break;
4023                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4024                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
4025                     replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
4026                     break;
4027                 /* Link configuration (IP address, DNS, ...) changes notified via netlink */
4028                 case CMD_UPDATE_LINKPROPERTIES:
4029                     updateLinkProperties((LinkProperties) message.obj);
4030                     break;
4031                 case CMD_GET_MATCHING_CONFIG:
4032                     replyToMessage(message, message.what);
4033                     break;
4034                 case CMD_GET_MATCHING_OSU_PROVIDERS:
4035                     replyToMessage(message, message.what, new ArrayList<OsuProvider>());
4036                     break;
4037                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
4038                 case CMD_IP_CONFIGURATION_LOST:
4039                 case CMD_IP_REACHABILITY_LOST:
4040                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
4041                     break;
4042                 case CMD_GET_CONNECTION_STATISTICS:
4043                     replyToMessage(message, message.what, mWifiConnectionStatistics);
4044                     break;
4045                 case CMD_REMOVE_APP_CONFIGURATIONS:
4046                     deferMessage(message);
4047                     break;
4048                 case CMD_REMOVE_USER_CONFIGURATIONS:
4049                     deferMessage(message);
4050                     break;
4051                 case CMD_START_IP_PACKET_OFFLOAD:
4052                     if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
4053                             message.arg1,
4054                             ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
4055                     break;
4056                 case CMD_STOP_IP_PACKET_OFFLOAD:
4057                     if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
4058                             message.arg1,
4059                             ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
4060                     break;
4061                 case CMD_START_RSSI_MONITORING_OFFLOAD:
4062                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
4063                     break;
4064                 case CMD_STOP_RSSI_MONITORING_OFFLOAD:
4065                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
4066                     break;
4067                 case CMD_USER_SWITCH:
4068                     Set<Integer> removedNetworkIds =
4069                             mWifiConfigManager.handleUserSwitch(message.arg1);
4070                     if (removedNetworkIds.contains(mTargetNetworkId) ||
4071                             removedNetworkIds.contains(mLastNetworkId)) {
4072                         // Disconnect and let autojoin reselect a new network
4073                         sendMessage(CMD_DISCONNECT);
4074                     }
4075                     break;
4076                 case CMD_USER_UNLOCK:
4077                     mWifiConfigManager.handleUserUnlock(message.arg1);
4078                     break;
4079                 case CMD_USER_STOP:
4080                     mWifiConfigManager.handleUserStop(message.arg1);
4081                     break;
4082                 case CMD_QUERY_OSU_ICON:
4083                 case CMD_MATCH_PROVIDER_NETWORK:
4084                     /* reply with arg1 = 0 - it returns API failure to the calling app
4085                      * (message.what is not looked at)
4086                      */
4087                     replyToMessage(message, message.what);
4088                     break;
4089                 case CMD_ADD_OR_UPDATE_PASSPOINT_CONFIG:
4090                     int addResult = mPasspointManager.addOrUpdateProvider(
4091                             (PasspointConfiguration) message.obj, message.arg1)
4092                             ? SUCCESS : FAILURE;
4093                     replyToMessage(message, message.what, addResult);
4094                     break;
4095                 case CMD_REMOVE_PASSPOINT_CONFIG:
4096                     int removeResult = mPasspointManager.removeProvider(
4097                             (String) message.obj) ? SUCCESS : FAILURE;
4098                     replyToMessage(message, message.what, removeResult);
4099                     break;
4100                 case CMD_GET_PASSPOINT_CONFIGS:
4101                     replyToMessage(message, message.what, mPasspointManager.getProviderConfigs());
4102                     break;
4103                 case CMD_RESET_SIM_NETWORKS:
4104                     /* Defer this message until supplicant is started. */
4105                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4106                     deferMessage(message);
4107                     break;
4108                 case CMD_INSTALL_PACKET_FILTER:
4109                     mWifiNative.installPacketFilter((byte[]) message.obj);
4110                     break;
4111                 case CMD_SET_FALLBACK_PACKET_FILTERING:
4112                     if ((boolean) message.obj) {
4113                         mWifiNative.startFilteringMulticastV4Packets();
4114                     } else {
4115                         mWifiNative.stopFilteringMulticastV4Packets();
4116                     }
4117                     break;
4118                 case CMD_CLIENT_INTERFACE_BINDER_DEATH:
4119                     Log.e(TAG, "wificond died unexpectedly. Triggering recovery");
4120                     mWifiMetrics.incrementNumWificondCrashes();
4121                     mWifiDiagnostics.captureBugReportData(
4122                             WifiDiagnostics.REPORT_REASON_WIFICOND_CRASH);
4123                     mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFICOND_CRASH);
4124                     break;
4125                 case CMD_VENDOR_HAL_HWBINDER_DEATH:
4126                     Log.e(TAG, "Vendor HAL died unexpectedly. Triggering recovery");
4127                     mWifiMetrics.incrementNumHalCrashes();
4128                     mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_HAL_CRASH);
4129                     mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_HAL_CRASH);
4130                     break;
4131                 case CMD_DIAGS_CONNECT_TIMEOUT:
4132                     mWifiDiagnostics.reportConnectionEvent(
4133                             (Long) message.obj, BaseWifiDiagnostics.CONNECTION_EVENT_FAILED);
4134                     break;
4135                 case 0:
4136                     // We want to notice any empty messages (with what == 0) that might crop up.
4137                     // For example, we may have recycled a message sent to multiple handlers.
4138                     Log.wtf(TAG, "Error! empty message encountered");
4139                     break;
4140                 default:
4141                     loge("Error! unhandled message" + message);
4142                     break;
4143             }
4144             return HANDLED;
4145         }
4146     }
4147 
4148     class InitialState extends State {
4149 
cleanup()4150         private void cleanup() {
4151             // Tearing down the client interfaces below is going to stop our supplicant.
4152             mWifiMonitor.stopAllMonitoring();
4153 
4154             mDeathRecipient.unlinkToDeath();
4155             mWifiNative.tearDown();
4156         }
4157 
4158         @Override
enter()4159         public void enter() {
4160             mWifiStateTracker.updateState(WifiStateTracker.INVALID);
4161             cleanup();
4162         }
4163 
4164         @Override
processMessage(Message message)4165         public boolean processMessage(Message message) {
4166             logStateAndMessage(message, this);
4167             switch (message.what) {
4168                 case CMD_START_SUPPLICANT:
4169                     Pair<Integer, IClientInterface> statusAndInterface =
4170                             mWifiNative.setupForClientMode();
4171                     if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
4172                         mClientInterface = statusAndInterface.second;
4173                     } else {
4174                         incrementMetricsForSetupFailure(statusAndInterface.first);
4175                     }
4176                     if (mClientInterface == null
4177                             || !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {
4178                         setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
4179                         cleanup();
4180                         break;
4181                     }
4182 
4183                     try {
4184                         // A runtime crash or shutting down AP mode can leave
4185                         // IP addresses configured, and this affects
4186                         // connectivity when supplicant starts up.
4187                         // Ensure we have no IP addresses before a supplicant start.
4188                         mNwService.clearInterfaceAddresses(mInterfaceName);
4189 
4190                         // Set privacy extensions
4191                         mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
4192 
4193                         // IPv6 is enabled only as long as access point is connected since:
4194                         // - IPv6 addresses and routes stick around after disconnection
4195                         // - kernel is unaware when connected and fails to start IPv6 negotiation
4196                         // - kernel can start autoconfiguration when 802.1x is not complete
4197                         mNwService.disableIpv6(mInterfaceName);
4198                     } catch (RemoteException re) {
4199                         loge("Unable to change interface settings: " + re);
4200                     } catch (IllegalStateException ie) {
4201                         loge("Unable to change interface settings: " + ie);
4202                     }
4203 
4204                     if (!mWifiNative.enableSupplicant()) {
4205                         loge("Failed to start supplicant!");
4206                         setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
4207                         cleanup();
4208                         break;
4209                     }
4210                     if (mVerboseLoggingEnabled) log("Supplicant start successful");
4211                     mWifiMonitor.startMonitoring(mInterfaceName, true);
4212                     mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
4213                     setSupplicantLogLevel();
4214                     transitionTo(mSupplicantStartingState);
4215                     break;
4216                 case CMD_START_AP:
4217                     transitionTo(mSoftApState);
4218                     break;
4219                 case CMD_SET_OPERATIONAL_MODE:
4220                     mOperationalMode = message.arg1;
4221                     if (mOperationalMode != DISABLED_MODE) {
4222                         sendMessage(CMD_START_SUPPLICANT);
4223                     }
4224                     break;
4225                 default:
4226                     return NOT_HANDLED;
4227             }
4228             return HANDLED;
4229         }
4230     }
4231 
4232     class SupplicantStartingState extends State {
initializeWpsDetails()4233         private void initializeWpsDetails() {
4234             String detail;
4235             detail = mPropertyService.get("ro.product.name", "");
4236             if (!mWifiNative.setDeviceName(detail)) {
4237                 loge("Failed to set device name " +  detail);
4238             }
4239             detail = mPropertyService.get("ro.product.manufacturer", "");
4240             if (!mWifiNative.setManufacturer(detail)) {
4241                 loge("Failed to set manufacturer " + detail);
4242             }
4243             detail = mPropertyService.get("ro.product.model", "");
4244             if (!mWifiNative.setModelName(detail)) {
4245                 loge("Failed to set model name " + detail);
4246             }
4247             detail = mPropertyService.get("ro.product.model", "");
4248             if (!mWifiNative.setModelNumber(detail)) {
4249                 loge("Failed to set model number " + detail);
4250             }
4251             detail = mPropertyService.get("ro.serialno", "");
4252             if (!mWifiNative.setSerialNumber(detail)) {
4253                 loge("Failed to set serial number " + detail);
4254             }
4255             if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
4256                 loge("Failed to set WPS config methods");
4257             }
4258             if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
4259                 loge("Failed to set primary device type " + mPrimaryDeviceType);
4260             }
4261         }
4262 
4263         @Override
processMessage(Message message)4264         public boolean processMessage(Message message) {
4265             logStateAndMessage(message, this);
4266 
4267             switch(message.what) {
4268                 case WifiMonitor.SUP_CONNECTION_EVENT:
4269                     if (mVerboseLoggingEnabled) log("Supplicant connection established");
4270 
4271                     mSupplicantRestartCount = 0;
4272                     /* Reset the supplicant state to indicate the supplicant
4273                      * state is not known at this time */
4274                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4275                     /* Initialize data structures */
4276                     mLastBssid = null;
4277                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4278                     mLastSignalLevel = -1;
4279 
4280                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
4281                     initializeWpsDetails();
4282                     sendSupplicantConnectionChangedBroadcast(true);
4283                     transitionTo(mSupplicantStartedState);
4284                     break;
4285                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
4286                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
4287                         loge("Failed to setup control channel, restart supplicant");
4288                         mWifiMonitor.stopAllMonitoring();
4289                         mWifiNative.disableSupplicant();
4290                         transitionTo(mInitialState);
4291                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4292                     } else {
4293                         loge("Failed " + mSupplicantRestartCount +
4294                                 " times to start supplicant, unload driver");
4295                         mSupplicantRestartCount = 0;
4296                         setWifiState(WIFI_STATE_UNKNOWN);
4297                         transitionTo(mInitialState);
4298                     }
4299                     break;
4300                 case CMD_START_SUPPLICANT:
4301                 case CMD_STOP_SUPPLICANT:
4302                 case CMD_START_AP:
4303                 case CMD_STOP_AP:
4304                 case CMD_SET_OPERATIONAL_MODE:
4305                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4306                     deferMessage(message);
4307                     break;
4308                 default:
4309                     return NOT_HANDLED;
4310             }
4311             return HANDLED;
4312         }
4313     }
4314 
4315     class SupplicantStartedState extends State {
4316         @Override
enter()4317         public void enter() {
4318             if (mVerboseLoggingEnabled) {
4319                 logd("SupplicantStartedState enter");
4320             }
4321 
4322             mWifiNative.setExternalSim(true);
4323 
4324             setRandomMacOui();
4325             mCountryCode.setReadyForChange(true);
4326 
4327             // We can't do this in the constructor because WifiStateMachine is created before the
4328             // wifi scanning service is initialized
4329             if (mWifiScanner == null) {
4330                 mWifiScanner = mWifiInjector.getWifiScanner();
4331 
4332                 synchronized (mWifiReqCountLock) {
4333                     mWifiConnectivityManager =
4334                             mWifiInjector.makeWifiConnectivityManager(mWifiInfo,
4335                                                                       hasConnectionRequests());
4336                     mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);
4337                     mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);
4338                 }
4339             }
4340 
4341             mWifiDiagnostics.startLogging(mVerboseLoggingEnabled);
4342             mIsRunning = true;
4343             updateBatteryWorkSource(null);
4344             /**
4345              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
4346              * When this mode is on, some of the low-level scan parameters used by the
4347              * driver are changed to reduce interference with bluetooth
4348              */
4349             mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4350             // Check if there is a voice call on-going and set/reset the tx power limit
4351             // appropriately.
4352             if (mEnableVoiceCallSarTxPowerLimit) {
4353                 if (getTelephonyManager().isOffhook()) {
4354                     sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
4355                             WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
4356                 } else {
4357                     sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
4358                             WifiNative.TX_POWER_SCENARIO_NORMAL);
4359                 }
4360             }
4361 
4362             // initialize network state
4363             setNetworkDetailedState(DetailedState.DISCONNECTED);
4364 
4365             // Disable legacy multicast filtering, which on some chipsets defaults to enabled.
4366             // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
4367             // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
4368             // IpManager.Callback.setFallbackMulticastFilter()
4369             mWifiNative.stopFilteringMulticastV4Packets();
4370             mWifiNative.stopFilteringMulticastV6Packets();
4371 
4372             if (mOperationalMode == SCAN_ONLY_MODE ||
4373                     mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4374                 mWifiNative.disconnect();
4375                 setWifiState(WIFI_STATE_DISABLED);
4376                 transitionTo(mScanModeState);
4377             } else if (mOperationalMode == CONNECT_MODE) {
4378                 setWifiState(WIFI_STATE_ENABLING);
4379                 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
4380                 transitionTo(mDisconnectedState);
4381             } else if (mOperationalMode == DISABLED_MODE) {
4382                 transitionTo(mSupplicantStoppingState);
4383             }
4384 
4385             // Set the right suspend mode settings
4386             mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
4387                     && mUserWantsSuspendOpt.get());
4388 
4389             mWifiNative.setPowerSave(true);
4390 
4391             if (mP2pSupported) {
4392                 if (mOperationalMode == CONNECT_MODE) {
4393                     p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
4394                 } else {
4395                     // P2P state machine starts in disabled state, and is not enabled until
4396                     // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
4397                     // keep it disabled.
4398                 }
4399             }
4400 
4401             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4402             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4403             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
4404             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4405 
4406             // Disable wpa_supplicant from auto reconnecting.
4407             mWifiNative.enableStaAutoReconnect(false);
4408             // STA has higher priority over P2P
4409             mWifiNative.setConcurrencyPriority(true);
4410         }
4411 
4412         @Override
processMessage(Message message)4413         public boolean processMessage(Message message) {
4414             logStateAndMessage(message, this);
4415 
4416             switch(message.what) {
4417                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
4418                     if (mP2pSupported) {
4419                         transitionTo(mWaitForP2pDisableState);
4420                     } else {
4421                         transitionTo(mSupplicantStoppingState);
4422                     }
4423                     break;
4424                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
4425                     loge("Connection lost, restart supplicant");
4426                     handleSupplicantConnectionLoss(true);
4427                     handleNetworkDisconnect();
4428                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4429                     if (mP2pSupported) {
4430                         transitionTo(mWaitForP2pDisableState);
4431                     } else {
4432                         transitionTo(mInitialState);
4433                     }
4434                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4435                     break;
4436                 case CMD_START_SCAN:
4437                     // TODO: remove scan request path (b/31445200)
4438                     handleScanRequest(message);
4439                     break;
4440                 case WifiMonitor.SCAN_RESULTS_EVENT:
4441                 case WifiMonitor.SCAN_FAILED_EVENT:
4442                     // TODO: remove handing of SCAN_RESULTS_EVENT and SCAN_FAILED_EVENT when scan
4443                     // results are retrieved from WifiScanner (b/31444878)
4444                     maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
4445                     setScanResults();
4446                     mIsScanOngoing = false;
4447                     mIsFullScanOngoing = false;
4448                     if (mBufferedScanMsg.size() > 0)
4449                         sendMessage(mBufferedScanMsg.remove());
4450                     break;
4451                 case CMD_START_AP:
4452                     /* Cannot start soft AP while in client mode */
4453                     loge("Failed to start soft AP with a running supplicant");
4454                     setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL,
4455                             null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
4456                     break;
4457                 case CMD_SET_OPERATIONAL_MODE:
4458                     mOperationalMode = message.arg1;
4459                     if (mOperationalMode == DISABLED_MODE) {
4460                         transitionTo(mSupplicantStoppingState);
4461                     }
4462                     break;
4463                 case CMD_TARGET_BSSID:
4464                     // Trying to associate to this BSSID
4465                     if (message.obj != null) {
4466                         mTargetRoamBSSID = (String) message.obj;
4467                     }
4468                     break;
4469                 case CMD_GET_LINK_LAYER_STATS:
4470                     WifiLinkLayerStats stats = getWifiLinkLayerStats();
4471                     replyToMessage(message, message.what, stats);
4472                     break;
4473                 case CMD_RESET_SIM_NETWORKS:
4474                     log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
4475                     mWifiConfigManager.resetSimNetworks(message.arg1 == 1);
4476                     break;
4477                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
4478                     mBluetoothConnectionActive = (message.arg1 !=
4479                             BluetoothAdapter.STATE_DISCONNECTED);
4480                     mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4481                     break;
4482                 case CMD_SET_SUSPEND_OPT_ENABLED:
4483                     if (message.arg1 == 1) {
4484                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
4485                         if (message.arg2 == 1) {
4486                             mSuspendWakeLock.release();
4487                         }
4488                     } else {
4489                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
4490                     }
4491                     break;
4492                 case CMD_SET_HIGH_PERF_MODE:
4493                     if (message.arg1 == 1) {
4494                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
4495                     } else {
4496                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
4497                     }
4498                     break;
4499                 case CMD_ENABLE_TDLS:
4500                     if (message.obj != null) {
4501                         String remoteAddress = (String) message.obj;
4502                         boolean enable = (message.arg1 == 1);
4503                         mWifiNative.startTdls(remoteAddress, enable);
4504                     }
4505                     break;
4506                 case WifiMonitor.ANQP_DONE_EVENT:
4507                     // TODO(zqiu): remove this when switch over to wificond for ANQP requests.
4508                     mPasspointManager.notifyANQPDone((AnqpEvent) message.obj);
4509                     break;
4510                 case CMD_STOP_IP_PACKET_OFFLOAD: {
4511                     int slot = message.arg1;
4512                     int ret = stopWifiIPPacketOffload(slot);
4513                     if (mNetworkAgent != null) {
4514                         mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
4515                     }
4516                     break;
4517                 }
4518                 case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4519                     // TODO(zqiu): remove this when switch over to wificond for icon requests.
4520                     mPasspointManager.notifyIconDone((IconEvent) message.obj);
4521                     break;
4522                 case WifiMonitor.HS20_REMEDIATION_EVENT:
4523                     // TODO(zqiu): remove this when switch over to wificond for WNM frames
4524                     // monitoring.
4525                     mPasspointManager.receivedWnmFrame((WnmData) message.obj);
4526                     break;
4527                 case CMD_CONFIG_ND_OFFLOAD:
4528                     final boolean enabled = (message.arg1 > 0);
4529                     mWifiNative.configureNeighborDiscoveryOffload(enabled);
4530                     break;
4531                 case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
4532                     mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
4533                     break;
4534                 case CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED:
4535                     final boolean allowed = (message.arg1 > 0);
4536                     boolean old_state = mEnableAutoJoinWhenAssociated;
4537                     mEnableAutoJoinWhenAssociated = allowed;
4538                     if (!old_state && allowed && mScreenOn
4539                             && getCurrentState() == mConnectedState) {
4540                         mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
4541                     }
4542                     break;
4543                 case CMD_SELECT_TX_POWER_SCENARIO:
4544                     int txPowerScenario = message.arg1;
4545                     logd("Setting Tx power scenario to " + txPowerScenario);
4546                     if (!mWifiNative.selectTxPowerScenario(txPowerScenario)) {
4547                         loge("Failed to set TX power scenario");
4548                     }
4549                     break;
4550                 default:
4551                     return NOT_HANDLED;
4552             }
4553             return HANDLED;
4554         }
4555 
4556         @Override
exit()4557         public void exit() {
4558             mWifiDiagnostics.stopLogging();
4559 
4560             mIsRunning = false;
4561             updateBatteryWorkSource(null);
4562             mScanResults = new ArrayList<>();
4563 
4564             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4565             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4566             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
4567             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4568             mBufferedScanMsg.clear();
4569 
4570             mNetworkInfo.setIsAvailable(false);
4571             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4572             mCountryCode.setReadyForChange(false);
4573         }
4574     }
4575 
4576     class SupplicantStoppingState extends State {
4577         @Override
enter()4578         public void enter() {
4579             /* Send any reset commands to supplicant before shutting it down */
4580             handleNetworkDisconnect();
4581 
4582             String suppState = System.getProperty("init.svc.wpa_supplicant");
4583             if (suppState == null) suppState = "unknown";
4584 
4585             setWifiState(WIFI_STATE_DISABLING);
4586             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4587             logd("SupplicantStoppingState: disableSupplicant "
4588                     + " init.svc.wpa_supplicant=" + suppState);
4589             if (mWifiNative.disableSupplicant()) {
4590                 mWifiNative.closeSupplicantConnection();
4591                 sendSupplicantConnectionChangedBroadcast(false);
4592                 setWifiState(WIFI_STATE_DISABLED);
4593             } else {
4594                 // Failed to disable supplicant
4595                 handleSupplicantConnectionLoss(true);
4596             }
4597             transitionTo(mInitialState);
4598         }
4599     }
4600 
4601     class WaitForP2pDisableState extends State {
4602         private State mTransitionToState;
4603         @Override
enter()4604         public void enter() {
4605             switch (getCurrentMessage().what) {
4606                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
4607                     mTransitionToState = mInitialState;
4608                     break;
4609                 case CMD_STOP_SUPPLICANT:
4610                 default:
4611                     mTransitionToState = mSupplicantStoppingState;
4612                     break;
4613             }
4614             if (p2pSendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ)) {
4615                 sendMessageDelayed(obtainMessage(CMD_DISABLE_P2P_WATCHDOG_TIMER,
4616                         mDisableP2pWatchdogCount, 0), DISABLE_P2P_GUARD_TIMER_MSEC);
4617             } else {
4618                 transitionTo(mTransitionToState);
4619             }
4620         }
4621         @Override
processMessage(Message message)4622         public boolean processMessage(Message message) {
4623             logStateAndMessage(message, this);
4624 
4625             switch(message.what) {
4626                 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
4627                     transitionTo(mTransitionToState);
4628                     break;
4629                 case WifiStateMachine.CMD_DISABLE_P2P_WATCHDOG_TIMER:
4630                     if (mDisableP2pWatchdogCount == message.arg1) {
4631                         logd("Timeout waiting for CMD_DISABLE_P2P_RSP");
4632                         transitionTo(mTransitionToState);
4633                     }
4634                     break;
4635                 /* Defer wifi start/shut and driver commands */
4636                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4637                 case CMD_START_SUPPLICANT:
4638                 case CMD_STOP_SUPPLICANT:
4639                 case CMD_START_AP:
4640                 case CMD_STOP_AP:
4641                 case CMD_SET_OPERATIONAL_MODE:
4642                 case CMD_START_SCAN:
4643                 case CMD_DISCONNECT:
4644                 case CMD_REASSOCIATE:
4645                 case CMD_RECONNECT:
4646                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4647                     deferMessage(message);
4648                     break;
4649                 default:
4650                     return NOT_HANDLED;
4651             }
4652             return HANDLED;
4653         }
4654     }
4655 
4656     class ScanModeState extends State {
4657         private int mLastOperationMode;
4658         @Override
enter()4659         public void enter() {
4660             mLastOperationMode = mOperationalMode;
4661             mWifiStateTracker.updateState(WifiStateTracker.SCAN_MODE);
4662         }
4663         @Override
processMessage(Message message)4664         public boolean processMessage(Message message) {
4665             logStateAndMessage(message, this);
4666 
4667             switch(message.what) {
4668                 case CMD_SET_OPERATIONAL_MODE:
4669                     if (message.arg1 == CONNECT_MODE) {
4670                         mOperationalMode = CONNECT_MODE;
4671                         setWifiState(WIFI_STATE_ENABLING);
4672                         transitionTo(mDisconnectedState);
4673                     } else if (message.arg1 == DISABLED_MODE) {
4674                         transitionTo(mSupplicantStoppingState);
4675                     }
4676                     // Nothing to do
4677                     break;
4678                 // Handle scan. All the connection related commands are
4679                 // handled only in ConnectModeState
4680                 case CMD_START_SCAN:
4681                     handleScanRequest(message);
4682                     break;
4683                 default:
4684                     return NOT_HANDLED;
4685             }
4686             return HANDLED;
4687         }
4688     }
4689 
4690 
smToString(Message message)4691     String smToString(Message message) {
4692         return smToString(message.what);
4693     }
4694 
smToString(int what)4695     String smToString(int what) {
4696         String s = sSmToString.get(what);
4697         if (s != null) {
4698             return s;
4699         }
4700         switch (what) {
4701             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
4702                 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
4703                 break;
4704             case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
4705                 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
4706                 break;
4707             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4708                 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
4709                 break;
4710             case WifiManager.DISABLE_NETWORK:
4711                 s = "WifiManager.DISABLE_NETWORK";
4712                 break;
4713             case WifiManager.CONNECT_NETWORK:
4714                 s = "CONNECT_NETWORK";
4715                 break;
4716             case WifiManager.SAVE_NETWORK:
4717                 s = "SAVE_NETWORK";
4718                 break;
4719             case WifiManager.FORGET_NETWORK:
4720                 s = "FORGET_NETWORK";
4721                 break;
4722             case WifiMonitor.SUP_CONNECTION_EVENT:
4723                 s = "SUP_CONNECTION_EVENT";
4724                 break;
4725             case WifiMonitor.SUP_DISCONNECTION_EVENT:
4726                 s = "SUP_DISCONNECTION_EVENT";
4727                 break;
4728             case WifiMonitor.SCAN_RESULTS_EVENT:
4729                 s = "SCAN_RESULTS_EVENT";
4730                 break;
4731             case WifiMonitor.SCAN_FAILED_EVENT:
4732                 s = "SCAN_FAILED_EVENT";
4733                 break;
4734             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4735                 s = "SUPPLICANT_STATE_CHANGE_EVENT";
4736                 break;
4737             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4738                 s = "AUTHENTICATION_FAILURE_EVENT";
4739                 break;
4740             case WifiMonitor.WPS_SUCCESS_EVENT:
4741                 s = "WPS_SUCCESS_EVENT";
4742                 break;
4743             case WifiMonitor.WPS_FAIL_EVENT:
4744                 s = "WPS_FAIL_EVENT";
4745                 break;
4746             case WifiMonitor.SUP_REQUEST_IDENTITY:
4747                 s = "SUP_REQUEST_IDENTITY";
4748                 break;
4749             case WifiMonitor.NETWORK_CONNECTION_EVENT:
4750                 s = "NETWORK_CONNECTION_EVENT";
4751                 break;
4752             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4753                 s = "NETWORK_DISCONNECTION_EVENT";
4754                 break;
4755             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4756                 s = "ASSOCIATION_REJECTION_EVENT";
4757                 break;
4758             case WifiMonitor.ANQP_DONE_EVENT:
4759                 s = "WifiMonitor.ANQP_DONE_EVENT";
4760                 break;
4761             case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4762                 s = "WifiMonitor.RX_HS20_ANQP_ICON_EVENT";
4763                 break;
4764             case WifiMonitor.GAS_QUERY_DONE_EVENT:
4765                 s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
4766                 break;
4767             case WifiMonitor.HS20_REMEDIATION_EVENT:
4768                 s = "WifiMonitor.HS20_REMEDIATION_EVENT";
4769                 break;
4770             case WifiMonitor.GAS_QUERY_START_EVENT:
4771                 s = "WifiMonitor.GAS_QUERY_START_EVENT";
4772                 break;
4773             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
4774                 s = "GROUP_CREATING_TIMED_OUT";
4775                 break;
4776             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
4777                 s = "P2P_CONNECTION_CHANGED";
4778                 break;
4779             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
4780                 s = "P2P.DISCONNECT_WIFI_RESPONSE";
4781                 break;
4782             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
4783                 s = "P2P.SET_MIRACAST_MODE";
4784                 break;
4785             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
4786                 s = "P2P.BLOCK_DISCOVERY";
4787                 break;
4788             case WifiManager.CANCEL_WPS:
4789                 s = "CANCEL_WPS";
4790                 break;
4791             case WifiManager.CANCEL_WPS_FAILED:
4792                 s = "CANCEL_WPS_FAILED";
4793                 break;
4794             case WifiManager.CANCEL_WPS_SUCCEDED:
4795                 s = "CANCEL_WPS_SUCCEDED";
4796                 break;
4797             case WifiManager.START_WPS:
4798                 s = "START_WPS";
4799                 break;
4800             case WifiManager.START_WPS_SUCCEEDED:
4801                 s = "START_WPS_SUCCEEDED";
4802                 break;
4803             case WifiManager.WPS_FAILED:
4804                 s = "WPS_FAILED";
4805                 break;
4806             case WifiManager.WPS_COMPLETED:
4807                 s = "WPS_COMPLETED";
4808                 break;
4809             case WifiManager.RSSI_PKTCNT_FETCH:
4810                 s = "RSSI_PKTCNT_FETCH";
4811                 break;
4812             default:
4813                 s = "what:" + Integer.toString(what);
4814                 break;
4815         }
4816         return s;
4817     }
4818 
registerConnected()4819     void registerConnected() {
4820         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4821             mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId);
4822             // On connect, reset wifiScoreReport
4823             mWifiScoreReport.reset();
4824 
4825             // Notify PasspointManager of Passpoint network connected event.
4826             WifiConfiguration currentNetwork = getCurrentWifiConfiguration();
4827             if (currentNetwork != null && currentNetwork.isPasspoint()) {
4828                 mPasspointManager.onPasspointNetworkConnected(currentNetwork.FQDN);
4829             }
4830        }
4831     }
4832 
registerDisconnected()4833     void registerDisconnected() {
4834         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4835             mWifiConfigManager.updateNetworkAfterDisconnect(mLastNetworkId);
4836             // Let's remove any ephemeral or passpoint networks on every disconnect.
4837             mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks();
4838         }
4839     }
4840 
4841     /**
4842      * Returns Wificonfiguration object correponding to the currently connected network, null if
4843      * not connected.
4844      */
getCurrentWifiConfiguration()4845     public WifiConfiguration getCurrentWifiConfiguration() {
4846         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
4847             return null;
4848         }
4849         return mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
4850     }
4851 
getCurrentScanResult()4852     ScanResult getCurrentScanResult() {
4853         WifiConfiguration config = getCurrentWifiConfiguration();
4854         if (config == null) {
4855             return null;
4856         }
4857         String BSSID = mWifiInfo.getBSSID();
4858         if (BSSID == null) {
4859             BSSID = mTargetRoamBSSID;
4860         }
4861         ScanDetailCache scanDetailCache =
4862                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
4863 
4864         if (scanDetailCache == null) {
4865             return null;
4866         }
4867 
4868         return scanDetailCache.getScanResult(BSSID);
4869     }
4870 
getCurrentBSSID()4871     String getCurrentBSSID() {
4872         if (isLinkDebouncing()) {
4873             return null;
4874         }
4875         return mLastBssid;
4876     }
4877 
4878     class ConnectModeState extends State {
4879 
4880         @Override
enter()4881         public void enter() {
4882             if (!mWifiNative.removeAllNetworks()) {
4883                 loge("Failed to remove networks on entering connect mode");
4884             }
4885             mWifiInfo.reset();
4886             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
4887             // Let the system know that wifi is available in client mode.
4888             setWifiState(WIFI_STATE_ENABLED);
4889 
4890             mNetworkInfo.setIsAvailable(true);
4891             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4892 
4893             // initialize network state
4894             setNetworkDetailedState(DetailedState.DISCONNECTED);
4895 
4896             // Inform WifiConnectivityManager that Wifi is enabled
4897             mWifiConnectivityManager.setWifiEnabled(true);
4898             // Inform metrics that Wifi is Enabled (but not yet connected)
4899             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
4900             // Inform p2p service that wifi is up and ready when applicable
4901             p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
4902         }
4903 
4904         @Override
exit()4905         public void exit() {
4906             // Let the system know that wifi is not available since we are exiting client mode.
4907             mNetworkInfo.setIsAvailable(false);
4908             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4909 
4910             // Inform WifiConnectivityManager that Wifi is disabled
4911             mWifiConnectivityManager.setWifiEnabled(false);
4912             // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
4913             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
4914 
4915             if (!mWifiNative.removeAllNetworks()) {
4916                 loge("Failed to remove networks on exiting connect mode");
4917             }
4918             mWifiInfo.reset();
4919             mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
4920         }
4921 
4922         @Override
processMessage(Message message)4923         public boolean processMessage(Message message) {
4924             WifiConfiguration config;
4925             int netId;
4926             boolean ok;
4927             boolean didDisconnect;
4928             String bssid;
4929             String ssid;
4930             NetworkUpdateResult result;
4931             Set<Integer> removedNetworkIds;
4932             int reasonCode;
4933             boolean timedOut;
4934             logStateAndMessage(message, this);
4935 
4936             switch (message.what) {
4937                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4938                     mWifiDiagnostics.captureBugReportData(
4939                             WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
4940                     didBlackListBSSID = false;
4941                     bssid = (String) message.obj;
4942                     timedOut = message.arg1 > 0;
4943                     reasonCode = message.arg2;
4944                     Log.d(TAG, "Assocation Rejection event: bssid=" + bssid + " reason code="
4945                             + reasonCode + " timedOut=" + Boolean.toString(timedOut));
4946                     if (bssid == null || TextUtils.isEmpty(bssid)) {
4947                         // If BSSID is null, use the target roam BSSID
4948                         bssid = mTargetRoamBSSID;
4949                     }
4950                     if (bssid != null) {
4951                         // If we have a BSSID, tell configStore to black list it
4952                         didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid, false,
4953                             reasonCode);
4954                     }
4955                     mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
4956                             WifiConfiguration.NetworkSelectionStatus
4957                             .DISABLED_ASSOCIATION_REJECTION);
4958                     mWifiConfigManager.setRecentFailureAssociationStatus(mTargetNetworkId,
4959                             reasonCode);
4960                     mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
4961                     // If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
4962                     reportConnectionAttemptEnd(
4963                             WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
4964                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
4965                     mWifiInjector.getWifiLastResortWatchdog()
4966                             .noteConnectionFailureAndTriggerIfNeeded(
4967                                     getTargetSsid(), bssid,
4968                                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
4969                     break;
4970                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4971                     mWifiDiagnostics.captureBugReportData(
4972                             WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
4973                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
4974                     int disableReason = WifiConfiguration.NetworkSelectionStatus
4975                             .DISABLED_AUTHENTICATION_FAILURE;
4976                     // Check if this is a permanent wrong password failure.
4977                     if (isPermanentWrongPasswordFailure(mTargetNetworkId, message.arg2)) {
4978                         disableReason = WifiConfiguration.NetworkSelectionStatus
4979                                 .DISABLED_BY_WRONG_PASSWORD;
4980                         WifiConfiguration targetedNetwork =
4981                                 mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
4982                         if (targetedNetwork != null) {
4983                             mWrongPasswordNotifier.onWrongPasswordError(
4984                                     targetedNetwork.SSID);
4985                         }
4986                     }
4987                     mWifiConfigManager.updateNetworkSelectionStatus(
4988                             mTargetNetworkId, disableReason);
4989                     mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);
4990                     //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
4991                     reportConnectionAttemptEnd(
4992                             WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
4993                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
4994                     mWifiInjector.getWifiLastResortWatchdog()
4995                             .noteConnectionFailureAndTriggerIfNeeded(
4996                                     getTargetSsid(), mTargetRoamBSSID,
4997                                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
4998                     break;
4999                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5000                     SupplicantState state = handleSupplicantStateChange(message);
5001                     // A driver/firmware hang can now put the interface in a down state.
5002                     // We detect the interface going down and recover from it
5003                     if (!SupplicantState.isDriverActive(state)) {
5004                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5005                             handleNetworkDisconnect();
5006                         }
5007                         log("Detected an interface down, restart driver");
5008                         // Rely on the fact that this will force us into killing supplicant and then
5009                         // restart supplicant from a clean state.
5010                         transitionTo(mSupplicantStoppingState);
5011                         sendMessage(CMD_START_SUPPLICANT);
5012                         break;
5013                     }
5014 
5015                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
5016                     // when authentication times out after a successful connection,
5017                     // we can figure this from the supplicant state. If supplicant
5018                     // state is DISCONNECTED, but the mNetworkInfo says we are not
5019                     // disconnected, we need to handle a disconnection
5020                     if (!isLinkDebouncing() && state == SupplicantState.DISCONNECTED &&
5021                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5022                         if (mVerboseLoggingEnabled) {
5023                             log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
5024                         }
5025                         handleNetworkDisconnect();
5026                         transitionTo(mDisconnectedState);
5027                     }
5028 
5029                     // If we have COMPLETED a connection to a BSSID, start doing
5030                     // DNAv4/DNAv6 -style probing for on-link neighbors of
5031                     // interest (e.g. routers); harmless if none are configured.
5032                     if (state == SupplicantState.COMPLETED) {
5033                         mIpManager.confirmConfiguration();
5034                     }
5035                     break;
5036                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5037                     if (message.arg1 == 1) {
5038                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5039                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
5040                         mWifiNative.disconnect();
5041                         mTemporarilyDisconnectWifi = true;
5042                     } else {
5043                         mWifiNative.reconnect();
5044                         mTemporarilyDisconnectWifi = false;
5045                     }
5046                     break;
5047                 case CMD_REMOVE_NETWORK:
5048                     if (!deleteNetworkConfigAndSendReply(message, false)) {
5049                         // failed to remove the config and caller was notified
5050                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5051                         break;
5052                     }
5053                     //  we successfully deleted the network config
5054                     netId = message.arg1;
5055                     if (netId == mTargetNetworkId || netId == mLastNetworkId) {
5056                         // Disconnect and let autojoin reselect a new network
5057                         sendMessage(CMD_DISCONNECT);
5058                     }
5059                     break;
5060                 case CMD_ENABLE_NETWORK:
5061                     boolean disableOthers = message.arg2 == 1;
5062                     netId = message.arg1;
5063                     if (disableOthers) {
5064                         // If the app has all the necessary permissions, this will trigger a connect
5065                         // attempt.
5066                         ok = connectToUserSelectNetwork(netId, message.sendingUid, false);
5067                     } else {
5068                         ok = mWifiConfigManager.enableNetwork(netId, false, message.sendingUid);
5069                     }
5070                     if (!ok) {
5071                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5072                     }
5073                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5074                     break;
5075                 case WifiManager.DISABLE_NETWORK:
5076                     netId = message.arg1;
5077                     if (mWifiConfigManager.disableNetwork(netId, message.sendingUid)) {
5078                         replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
5079                         if (netId == mTargetNetworkId || netId == mLastNetworkId) {
5080                             // Disconnect and let autojoin reselect a new network
5081                             sendMessage(CMD_DISCONNECT);
5082                         }
5083                     } else {
5084                         loge("Failed to disable network");
5085                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5086                         replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5087                                 WifiManager.ERROR);
5088                     }
5089                     break;
5090                 case CMD_DISABLE_EPHEMERAL_NETWORK:
5091                     config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
5092                     if (config != null) {
5093                         if (config.networkId == mTargetNetworkId
5094                                 || config.networkId == mLastNetworkId) {
5095                             // Disconnect and let autojoin reselect a new network
5096                             sendMessage(CMD_DISCONNECT);
5097                         }
5098                     }
5099                     break;
5100                 case CMD_SAVE_CONFIG:
5101                     ok = mWifiConfigManager.saveToStore(true);
5102                     replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
5103                     // Inform the backup manager about a data change
5104                     mBackupManagerProxy.notifyDataChanged();
5105                     break;
5106                 case WifiMonitor.SUP_REQUEST_IDENTITY:
5107                     int supplicantNetworkId = message.arg2;
5108                     netId = lookupFrameworkNetworkId(supplicantNetworkId);
5109                     boolean identitySent = false;
5110                     // For SIM & AKA/AKA' EAP method Only, get identity from ICC
5111                     if (targetWificonfiguration != null
5112                             && targetWificonfiguration.networkId == netId
5113                             && TelephonyUtil.isSimConfig(targetWificonfiguration)) {
5114                         String identity =
5115                                 TelephonyUtil.getSimIdentity(getTelephonyManager(),
5116                                         targetWificonfiguration);
5117                         if (identity != null) {
5118                             mWifiNative.simIdentityResponse(supplicantNetworkId, identity);
5119                             identitySent = true;
5120                         } else {
5121                             Log.e(TAG, "Unable to retrieve identity from Telephony");
5122                         }
5123                     }
5124                     if (!identitySent) {
5125                         // Supplicant lacks credentials to connect to that network, hence black list
5126                         ssid = (String) message.obj;
5127                         if (targetWificonfiguration != null && ssid != null
5128                                 && targetWificonfiguration.SSID != null
5129                                 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
5130                             mWifiConfigManager.updateNetworkSelectionStatus(
5131                                     targetWificonfiguration.networkId,
5132                                     WifiConfiguration.NetworkSelectionStatus
5133                                             .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
5134                         }
5135                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5136                                 StaEvent.DISCONNECT_GENERIC);
5137                         mWifiNative.disconnect();
5138                     }
5139                     break;
5140                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5141                     logd("Received SUP_REQUEST_SIM_AUTH");
5142                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5143                     if (requestData != null) {
5144                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5145                             handleGsmAuthRequest(requestData);
5146                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5147                             || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5148                             handle3GAuthRequest(requestData);
5149                         }
5150                     } else {
5151                         loge("Invalid sim auth request");
5152                     }
5153                     break;
5154                 case CMD_GET_MATCHING_CONFIG:
5155                     replyToMessage(message, message.what,
5156                             mPasspointManager.getMatchingWifiConfig((ScanResult) message.obj));
5157                     break;
5158                 case CMD_GET_MATCHING_OSU_PROVIDERS:
5159                     replyToMessage(message, message.what,
5160                             mPasspointManager.getMatchingOsuProviders((ScanResult) message.obj));
5161                     break;
5162                 case CMD_RECONNECT:
5163                     WorkSource workSource = (WorkSource) message.obj;
5164                     mWifiConnectivityManager.forceConnectivityScan(workSource);
5165                     break;
5166                 case CMD_REASSOCIATE:
5167                     lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5168                     mWifiNative.reassociate();
5169                     break;
5170                 case CMD_RELOAD_TLS_AND_RECONNECT:
5171                     if (mWifiConfigManager.needsUnlockedKeyStore()) {
5172                         logd("Reconnecting to give a chance to un-connected TLS networks");
5173                         mWifiNative.disconnect();
5174                         lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5175                         mWifiNative.reconnect();
5176                     }
5177                     break;
5178                 case CMD_START_ROAM:
5179                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5180                     return HANDLED;
5181                 case CMD_START_CONNECT:
5182                     /* connect command coming from auto-join */
5183                     netId = message.arg1;
5184                     int uid = message.arg2;
5185                     bssid = (String) message.obj;
5186 
5187                     synchronized (mWifiReqCountLock) {
5188                         if (!hasConnectionRequests()) {
5189                             if (mNetworkAgent == null) {
5190                                 loge("CMD_START_CONNECT but no requests and not connected,"
5191                                         + " bailing");
5192                                 break;
5193                             } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
5194                                 loge("CMD_START_CONNECT but no requests and connected, but app "
5195                                         + "does not have sufficient permissions, bailing");
5196                                 break;
5197                             }
5198                         }
5199                     }
5200 
5201                     config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
5202                     logd("CMD_START_CONNECT sup state "
5203                             + mSupplicantStateTracker.getSupplicantStateName()
5204                             + " my state " + getCurrentState().getName()
5205                             + " nid=" + Integer.toString(netId)
5206                             + " roam=" + Boolean.toString(mIsAutoRoaming));
5207                     if (config == null) {
5208                         loge("CMD_START_CONNECT and no config, bail out...");
5209                         break;
5210                     }
5211                     mTargetNetworkId = netId;
5212                     setTargetBssid(config, bssid);
5213 
5214                     reportConnectionAttemptStart(config, mTargetRoamBSSID,
5215                             WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
5216                     if (mWifiNative.connectToNetwork(config)) {
5217                         mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
5218                         lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5219                         targetWificonfiguration = config;
5220                         mIsAutoRoaming = false;
5221                         if (isLinkDebouncing()) {
5222                             transitionTo(mRoamingState);
5223                         } else if (getCurrentState() != mDisconnectedState) {
5224                             transitionTo(mDisconnectingState);
5225                         }
5226                     } else {
5227                         loge("CMD_START_CONNECT Failed to start connection to network " + config);
5228                         reportConnectionAttemptEnd(
5229                                 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5230                                 WifiMetricsProto.ConnectionEvent.HLF_NONE);
5231                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5232                                 WifiManager.ERROR);
5233                         break;
5234                     }
5235                     break;
5236                 case CMD_REMOVE_APP_CONFIGURATIONS:
5237                     removedNetworkIds =
5238                             mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
5239                     if (removedNetworkIds.contains(mTargetNetworkId) ||
5240                             removedNetworkIds.contains(mLastNetworkId)) {
5241                         // Disconnect and let autojoin reselect a new network.
5242                         sendMessage(CMD_DISCONNECT);
5243                     }
5244                     break;
5245                 case CMD_REMOVE_USER_CONFIGURATIONS:
5246                     removedNetworkIds =
5247                             mWifiConfigManager.removeNetworksForUser((Integer) message.arg1);
5248                     if (removedNetworkIds.contains(mTargetNetworkId) ||
5249                             removedNetworkIds.contains(mLastNetworkId)) {
5250                         // Disconnect and let autojoin reselect a new network.
5251                         sendMessage(CMD_DISCONNECT);
5252                     }
5253                     break;
5254                 case WifiManager.CONNECT_NETWORK:
5255                     /**
5256                      * The connect message can contain a network id passed as arg1 on message or
5257                      * or a config passed as obj on message.
5258                      * For a new network, a config is passed to create and connect.
5259                      * For an existing network, a network id is passed
5260                      */
5261                     netId = message.arg1;
5262                     config = (WifiConfiguration) message.obj;
5263                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5264                     boolean hasCredentialChanged = false;
5265                     // New network addition.
5266                     if (config != null) {
5267                         result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5268                         if (!result.isSuccess()) {
5269                             loge("CONNECT_NETWORK adding/updating config=" + config + " failed");
5270                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5271                             replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5272                                     WifiManager.ERROR);
5273                             break;
5274                         }
5275                         netId = result.getNetworkId();
5276                         hasCredentialChanged = result.hasCredentialChanged();
5277                     }
5278                     if (!connectToUserSelectNetwork(
5279                             netId, message.sendingUid, hasCredentialChanged)) {
5280                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5281                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5282                                 WifiManager.NOT_AUTHORIZED);
5283                         break;
5284                     }
5285                     mWifiMetrics.logStaEvent(StaEvent.TYPE_CONNECT_NETWORK, config);
5286                     broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
5287                     replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
5288                     break;
5289                 case WifiManager.SAVE_NETWORK:
5290                     result = saveNetworkConfigAndSendReply(message);
5291                     netId = result.getNetworkId();
5292                     if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
5293                         mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5294                         if (result.hasCredentialChanged()) {
5295                             config = (WifiConfiguration) message.obj;
5296                             // The network credentials changed and we're connected to this network,
5297                             // start a new connection with the updated credentials.
5298                             logi("SAVE_NETWORK credential changed for config=" + config.configKey()
5299                                     + ", Reconnecting.");
5300                             startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
5301                         } else {
5302                             if (result.hasProxyChanged()) {
5303                                 log("Reconfiguring proxy on connection");
5304                                 mIpManager.setHttpProxy(
5305                                         getCurrentWifiConfiguration().getHttpProxy());
5306                             }
5307                             if (result.hasIpChanged()) {
5308                                 // The current connection configuration was changed
5309                                 // We switched from DHCP to static or from static to DHCP, or the
5310                                 // static IP address has changed.
5311                                 log("Reconfiguring IP on connection");
5312                                 // TODO(b/36576642): clear addresses and disable IPv6
5313                                 // to simplify obtainingIpState.
5314                                 transitionTo(mObtainingIpState);
5315                             }
5316                         }
5317                     }
5318                     break;
5319                 case WifiManager.FORGET_NETWORK:
5320                     if (!deleteNetworkConfigAndSendReply(message, true)) {
5321                         // Caller was notified of failure, nothing else to do
5322                         break;
5323                     }
5324                     // the network was deleted
5325                     netId = message.arg1;
5326                     if (netId == mTargetNetworkId || netId == mLastNetworkId) {
5327                         // Disconnect and let autojoin reselect a new network
5328                         sendMessage(CMD_DISCONNECT);
5329                     }
5330                     break;
5331                 case WifiManager.START_WPS:
5332                     WpsInfo wpsInfo = (WpsInfo) message.obj;
5333                     if (wpsInfo == null) {
5334                         loge("Cannot start WPS with null WpsInfo object");
5335                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
5336                         break;
5337                     }
5338                     WpsResult wpsResult = new WpsResult();
5339                     // TODO(b/32898136): Not needed when we start deleting networks from supplicant
5340                     // on disconnect.
5341                     if (!mWifiNative.removeAllNetworks()) {
5342                         loge("Failed to remove networks before WPS");
5343                     }
5344                     switch (wpsInfo.setup) {
5345                         case WpsInfo.PBC:
5346                             if (mWifiNative.startWpsPbc(wpsInfo.BSSID)) {
5347                                 wpsResult.status = WpsResult.Status.SUCCESS;
5348                             } else {
5349                                 Log.e(TAG, "Failed to start WPS push button configuration");
5350                                 wpsResult.status = WpsResult.Status.FAILURE;
5351                             }
5352                             break;
5353                         case WpsInfo.KEYPAD:
5354                             if (mWifiNative.startWpsRegistrar(wpsInfo.BSSID, wpsInfo.pin)) {
5355                                 wpsResult.status = WpsResult.Status.SUCCESS;
5356                             } else {
5357                                 Log.e(TAG, "Failed to start WPS push button configuration");
5358                                 wpsResult.status = WpsResult.Status.FAILURE;
5359                             }
5360                             break;
5361                         case WpsInfo.DISPLAY:
5362                             wpsResult.pin = mWifiNative.startWpsPinDisplay(wpsInfo.BSSID);
5363                             if (!TextUtils.isEmpty(wpsResult.pin)) {
5364                                 wpsResult.status = WpsResult.Status.SUCCESS;
5365                             } else {
5366                                 Log.e(TAG, "Failed to start WPS pin method configuration");
5367                                 wpsResult.status = WpsResult.Status.FAILURE;
5368                             }
5369                             break;
5370                         default:
5371                             wpsResult = new WpsResult(Status.FAILURE);
5372                             loge("Invalid setup for WPS");
5373                             break;
5374                     }
5375                     if (wpsResult.status == Status.SUCCESS) {
5376                         replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
5377                         transitionTo(mWpsRunningState);
5378                     } else {
5379                         loge("Failed to start WPS with config " + wpsInfo.toString());
5380                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
5381                     }
5382                     break;
5383                 case CMD_ASSOCIATED_BSSID:
5384                     // This is where we can confirm the connection BSSID. Use it to find the
5385                     // right ScanDetail to populate metrics.
5386                     String someBssid = (String) message.obj;
5387                     if (someBssid != null) {
5388                         // Get the ScanDetail associated with this BSSID.
5389                         ScanDetailCache scanDetailCache =
5390                                 mWifiConfigManager.getScanDetailCacheForNetwork(mTargetNetworkId);
5391                         if (scanDetailCache != null) {
5392                             mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
5393                                     someBssid));
5394                         }
5395                     }
5396                     return NOT_HANDLED;
5397                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5398                     if (mVerboseLoggingEnabled) log("Network connection established");
5399                     mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
5400                     mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
5401                     mLastBssid = (String) message.obj;
5402                     reasonCode = message.arg2;
5403                     // TODO: This check should not be needed after WifiStateMachinePrime refactor.
5404                     // Currently, the last connected network configuration is left in
5405                     // wpa_supplicant, this may result in wpa_supplicant initiating connection
5406                     // to it after a config store reload. Hence the old network Id lookups may not
5407                     // work, so disconnect the network and let network selector reselect a new
5408                     // network.
5409                     config = getCurrentWifiConfiguration();
5410                     if (config != null) {
5411                         mWifiInfo.setBSSID(mLastBssid);
5412                         mWifiInfo.setNetworkId(mLastNetworkId);
5413 
5414                         ScanDetailCache scanDetailCache =
5415                                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
5416                         if (scanDetailCache != null && mLastBssid != null) {
5417                             ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
5418                             if (scanResult != null) {
5419                                 mWifiInfo.setFrequency(scanResult.frequency);
5420                             }
5421                         }
5422                         mWifiConnectivityManager.trackBssid(mLastBssid, true, reasonCode);
5423                         // We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA'
5424                         if (config.enterpriseConfig != null
5425                                 && TelephonyUtil.isSimEapMethod(
5426                                         config.enterpriseConfig.getEapMethod())) {
5427                             String anonymousIdentity = mWifiNative.getEapAnonymousIdentity();
5428                             if (anonymousIdentity != null) {
5429                                 config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
5430                             } else {
5431                                 Log.d(TAG, "Failed to get updated anonymous identity"
5432                                         + " from supplicant, reset it in WifiConfiguration.");
5433                                 config.enterpriseConfig.setAnonymousIdentity(null);
5434                             }
5435                             mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
5436                         }
5437                         sendNetworkStateChangeBroadcast(mLastBssid);
5438                         transitionTo(mObtainingIpState);
5439                     } else {
5440                         logw("Connected to unknown networkId " + mLastNetworkId
5441                                 + ", disconnecting...");
5442                         sendMessage(CMD_DISCONNECT);
5443                     }
5444                     break;
5445                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5446                     // Calling handleNetworkDisconnect here is redundant because we might already
5447                     // have called it when leaving L2ConnectedState to go to disconnecting state
5448                     // or thru other path
5449                     // We should normally check the mWifiInfo or mLastNetworkId so as to check
5450                     // if they are valid, and only in this case call handleNEtworkDisconnect,
5451                     // TODO: this should be fixed for a L MR release
5452                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of
5453                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
5454                     // at the chip etc...
5455                     if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
5456                     handleNetworkDisconnect();
5457                     transitionTo(mDisconnectedState);
5458                     break;
5459                 case CMD_QUERY_OSU_ICON:
5460                     mPasspointManager.queryPasspointIcon(
5461                             ((Bundle) message.obj).getLong(EXTRA_OSU_ICON_QUERY_BSSID),
5462                             ((Bundle) message.obj).getString(EXTRA_OSU_ICON_QUERY_FILENAME));
5463                     break;
5464                 case CMD_MATCH_PROVIDER_NETWORK:
5465                     // TODO(b/31065385): Passpoint config management.
5466                     replyToMessage(message, message.what, 0);
5467                     break;
5468                 case CMD_ADD_OR_UPDATE_PASSPOINT_CONFIG:
5469                     PasspointConfiguration passpointConfig = (PasspointConfiguration) message.obj;
5470                     if (mPasspointManager.addOrUpdateProvider(passpointConfig, message.arg1)) {
5471                         String fqdn = passpointConfig.getHomeSp().getFqdn();
5472                         if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
5473                                 || isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
5474                             logd("Disconnect from current network since its provider is updated");
5475                             sendMessage(CMD_DISCONNECT);
5476                         }
5477                         replyToMessage(message, message.what, SUCCESS);
5478                     } else {
5479                         replyToMessage(message, message.what, FAILURE);
5480                     }
5481                     break;
5482                 case CMD_REMOVE_PASSPOINT_CONFIG:
5483                     String fqdn = (String) message.obj;
5484                     if (mPasspointManager.removeProvider(fqdn)) {
5485                         if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
5486                                 || isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
5487                             logd("Disconnect from current network since its provider is removed");
5488                             sendMessage(CMD_DISCONNECT);
5489                         }
5490                         replyToMessage(message, message.what, SUCCESS);
5491                     } else {
5492                         replyToMessage(message, message.what, FAILURE);
5493                     }
5494                     break;
5495                 case CMD_ENABLE_P2P:
5496                     p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
5497                     break;
5498                 default:
5499                     return NOT_HANDLED;
5500             }
5501             return HANDLED;
5502         }
5503     }
5504 
updateCapabilities()5505     public void updateCapabilities() {
5506         updateCapabilities(getCurrentWifiConfiguration());
5507     }
5508 
updateCapabilities(WifiConfiguration config)5509     private void updateCapabilities(WifiConfiguration config) {
5510         final NetworkCapabilities result = new NetworkCapabilities(mDfltNetworkCapabilities);
5511 
5512         if (mWifiInfo != null && !mWifiInfo.isEphemeral()) {
5513             result.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5514         } else {
5515             result.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5516         }
5517 
5518         if (mWifiInfo != null && !WifiConfiguration.isMetered(config, mWifiInfo)) {
5519             result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5520         } else {
5521             result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5522         }
5523 
5524         if (mWifiInfo != null && mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI) {
5525             result.setSignalStrength(mWifiInfo.getRssi());
5526         } else {
5527             result.setSignalStrength(NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
5528         }
5529 
5530         if (mNetworkAgent != null) {
5531             mNetworkAgent.sendNetworkCapabilities(result);
5532         }
5533     }
5534 
5535     /**
5536      * Checks if the given network |networkdId| is provided by the given Passpoint provider with
5537      * |providerFqdn|.
5538      *
5539      * @param networkId The ID of the network to check
5540      * @param providerFqdn The FQDN of the Passpoint provider
5541      * @return true if the given network is provided by the given Passpoint provider
5542      */
isProviderOwnedNetwork(int networkId, String providerFqdn)5543     private boolean isProviderOwnedNetwork(int networkId, String providerFqdn) {
5544         if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
5545             return false;
5546         }
5547         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId);
5548         if (config == null) {
5549             return false;
5550         }
5551         return TextUtils.equals(config.FQDN, providerFqdn);
5552     }
5553 
5554     private class WifiNetworkAgent extends NetworkAgent {
WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc)5555         public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
5556                 NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
5557             super(l, c, TAG, ni, nc, lp, score, misc);
5558         }
5559 
5560         @Override
unwanted()5561         protected void unwanted() {
5562             // Ignore if we're not the current networkAgent.
5563             if (this != mNetworkAgent) return;
5564             if (mVerboseLoggingEnabled) {
5565                 log("WifiNetworkAgent -> Wifi unwanted score " + Integer.toString(mWifiInfo.score));
5566             }
5567             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
5568         }
5569 
5570         @Override
networkStatus(int status, String redirectUrl)5571         protected void networkStatus(int status, String redirectUrl) {
5572             if (this != mNetworkAgent) return;
5573             if (status == NetworkAgent.INVALID_NETWORK) {
5574                 if (mVerboseLoggingEnabled) {
5575                     log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
5576                             + Integer.toString(mWifiInfo.score));
5577                 }
5578                 unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
5579             } else if (status == NetworkAgent.VALID_NETWORK) {
5580                 if (mVerboseLoggingEnabled) {
5581                     log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
5582                             + Integer.toString(mWifiInfo.score));
5583                 }
5584                 mWifiMetrics.logStaEvent(StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
5585                 doNetworkStatus(status);
5586             }
5587         }
5588 
5589         @Override
saveAcceptUnvalidated(boolean accept)5590         protected void saveAcceptUnvalidated(boolean accept) {
5591             if (this != mNetworkAgent) return;
5592             WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
5593         }
5594 
5595         @Override
startPacketKeepalive(Message msg)5596         protected void startPacketKeepalive(Message msg) {
5597             WifiStateMachine.this.sendMessage(
5598                     CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5599         }
5600 
5601         @Override
stopPacketKeepalive(Message msg)5602         protected void stopPacketKeepalive(Message msg) {
5603             WifiStateMachine.this.sendMessage(
5604                     CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5605         }
5606 
5607         @Override
setSignalStrengthThresholds(int[] thresholds)5608         protected void setSignalStrengthThresholds(int[] thresholds) {
5609             // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
5610             // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
5611             //    MAX_VALUE at the start/end of the thresholds array if necessary.
5612             // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
5613             //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
5614             //    re-arm the hardware event. This needs to be done on the state machine thread to
5615             //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
5616             //    sent in the NetworkCapabilities) must be the one received from the hardware event
5617             //    received, or we might skip callbacks.
5618             // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
5619             log("Received signal strength thresholds: " + Arrays.toString(thresholds));
5620             if (thresholds.length == 0) {
5621                 WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5622                         mWifiInfo.getRssi());
5623                 return;
5624             }
5625             int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
5626             rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
5627             rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
5628             Arrays.sort(rssiVals);
5629             byte[] rssiRange = new byte[rssiVals.length];
5630             for (int i = 0; i < rssiVals.length; i++) {
5631                 int val = rssiVals[i];
5632                 if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
5633                     rssiRange[i] = (byte) val;
5634                 } else {
5635                     Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
5636                             + Arrays.toString(rssiVals));
5637                     WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5638                             mWifiInfo.getRssi());
5639                     return;
5640                 }
5641             }
5642             // TODO: Do we quash rssi values in this sorted array which are very close?
5643             mRssiRanges = rssiRange;
5644             WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
5645                     mWifiInfo.getRssi());
5646         }
5647 
5648         @Override
preventAutomaticReconnect()5649         protected void preventAutomaticReconnect() {
5650             if (this != mNetworkAgent) return;
5651             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
5652         }
5653     }
5654 
unwantedNetwork(int reason)5655     void unwantedNetwork(int reason) {
5656         sendMessage(CMD_UNWANTED_NETWORK, reason);
5657     }
5658 
doNetworkStatus(int status)5659     void doNetworkStatus(int status) {
5660         sendMessage(CMD_NETWORK_STATUS, status);
5661     }
5662 
5663     // rfc4186 & rfc4187:
5664     // create Permanent Identity base on IMSI,
5665     // identity = usernam@realm
5666     // with username = prefix | IMSI
5667     // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
buildIdentity(int eapMethod, String imsi, String mccMnc)5668     private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
5669         String mcc;
5670         String mnc;
5671         String prefix;
5672 
5673         if (imsi == null || imsi.isEmpty())
5674             return "";
5675 
5676         if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
5677             prefix = "1";
5678         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
5679             prefix = "0";
5680         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
5681             prefix = "6";
5682         else  // not a valide EapMethod
5683             return "";
5684 
5685         /* extract mcc & mnc from mccMnc */
5686         if (mccMnc != null && !mccMnc.isEmpty()) {
5687             mcc = mccMnc.substring(0, 3);
5688             mnc = mccMnc.substring(3);
5689             if (mnc.length() == 2)
5690                 mnc = "0" + mnc;
5691         } else {
5692             // extract mcc & mnc from IMSI, assume mnc size is 3
5693             mcc = imsi.substring(0, 3);
5694             mnc = imsi.substring(3, 6);
5695         }
5696 
5697         return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
5698     }
5699 
startScanForConfiguration(WifiConfiguration config)5700     boolean startScanForConfiguration(WifiConfiguration config) {
5701         if (config == null)
5702             return false;
5703 
5704         // We are still seeing a fairly high power consumption triggered by autojoin scans
5705         // Hence do partial scans only for PSK configuration that are roamable since the
5706         // primary purpose of the partial scans is roaming.
5707         // Full badn scans with exponential backoff for the purpose or extended roaming and
5708         // network switching are performed unconditionally.
5709         ScanDetailCache scanDetailCache =
5710                 mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
5711         if (scanDetailCache == null
5712                 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
5713                 || scanDetailCache.size() > 6) {
5714             //return true but to not trigger the scan
5715             return true;
5716         }
5717         Set<Integer> freqs =
5718                 mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(
5719                         config.networkId, ONE_HOUR_MILLI, mWifiInfo.getFrequency());
5720         if (freqs != null && freqs.size() != 0) {
5721             //if (mVerboseLoggingEnabled) {
5722             logd("starting scan for " + config.configKey() + " with " + freqs);
5723             //}
5724             List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks = new ArrayList<>();
5725             if (config.hiddenSSID) {
5726                 hiddenNetworks.add(new WifiScanner.ScanSettings.HiddenNetwork(config.SSID));
5727             }
5728             // Call wifi native to start the scan
5729             if (startScanNative(freqs, hiddenNetworks, WIFI_WORK_SOURCE)) {
5730                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
5731             } else {
5732                 // used for debug only, mark scan as failed
5733                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
5734             }
5735             return true;
5736         } else {
5737             if (mVerboseLoggingEnabled) logd("no channels for " + config.configKey());
5738             return false;
5739         }
5740     }
5741 
5742     class L2ConnectedState extends State {
5743         @Override
enter()5744         public void enter() {
5745             mRssiPollToken++;
5746             if (mEnableRssiPolling) {
5747                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
5748             }
5749             if (mNetworkAgent != null) {
5750                 loge("Have NetworkAgent when entering L2Connected");
5751                 setNetworkDetailedState(DetailedState.DISCONNECTED);
5752             }
5753             setNetworkDetailedState(DetailedState.CONNECTING);
5754 
5755             mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
5756                     "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
5757                     mLinkProperties, 60, mNetworkMisc);
5758 
5759             // We must clear the config BSSID, as the wifi chipset may decide to roam
5760             // from this point on and having the BSSID specified in the network block would
5761             // cause the roam to faile and the device to disconnect
5762             clearTargetBssid("L2ConnectedState");
5763             mCountryCode.setReadyForChange(false);
5764             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
5765         }
5766 
5767         @Override
exit()5768         public void exit() {
5769             mIpManager.stop();
5770 
5771             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
5772             // Bug: 15347363
5773             // For paranoia's sake, call handleNetworkDisconnect
5774             // only if BSSID is null or last networkId
5775             // is not invalid.
5776             if (mVerboseLoggingEnabled) {
5777                 StringBuilder sb = new StringBuilder();
5778                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
5779                 if (mLastBssid !=null) {
5780                     sb.append(" ").append(mLastBssid);
5781                 }
5782             }
5783             if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5784                 handleNetworkDisconnect();
5785             }
5786             mCountryCode.setReadyForChange(true);
5787             mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
5788         }
5789 
5790         @Override
processMessage(Message message)5791         public boolean processMessage(Message message) {
5792             logStateAndMessage(message, this);
5793 
5794             switch (message.what) {
5795                 case DhcpClient.CMD_PRE_DHCP_ACTION:
5796                     handlePreDhcpSetup();
5797                     break;
5798                 case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
5799                     mIpManager.completedPreDhcpAction();
5800                     break;
5801                 case DhcpClient.CMD_POST_DHCP_ACTION:
5802                     handlePostDhcpSetup();
5803                     // We advance to mConnectedState because IpManager will also send a
5804                     // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
5805                     // which calls updateLinkProperties, which then sends
5806                     // CMD_IP_CONFIGURATION_SUCCESSFUL.
5807                     //
5808                     // In the event of failure, we transition to mDisconnectingState
5809                     // similarly--via messages sent back from IpManager.
5810                     break;
5811                 case CMD_IPV4_PROVISIONING_SUCCESS: {
5812                     handleIPv4Success((DhcpResults) message.obj);
5813                     sendNetworkStateChangeBroadcast(mLastBssid);
5814                     break;
5815                 }
5816                 case CMD_IPV4_PROVISIONING_FAILURE: {
5817                     handleIPv4Failure();
5818                     break;
5819                 }
5820                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
5821                     handleSuccessfulIpConfiguration();
5822                     reportConnectionAttemptEnd(
5823                             WifiMetrics.ConnectionEvent.FAILURE_NONE,
5824                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
5825                     if (getCurrentWifiConfiguration() == null) {
5826                         // The current config may have been removed while we were connecting,
5827                         // trigger a disconnect to clear up state.
5828                         mWifiNative.disconnect();
5829                         transitionTo(mDisconnectingState);
5830                     } else {
5831                         sendConnectedState();
5832                         transitionTo(mConnectedState);
5833                     }
5834                     break;
5835                 case CMD_IP_CONFIGURATION_LOST:
5836                     // Get Link layer stats so that we get fresh tx packet counters.
5837                     getWifiLinkLayerStats();
5838                     handleIpConfigurationLost();
5839                     reportConnectionAttemptEnd(
5840                             WifiMetrics.ConnectionEvent.FAILURE_DHCP,
5841                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
5842                     transitionTo(mDisconnectingState);
5843                     break;
5844                 case CMD_IP_REACHABILITY_LOST:
5845                     if (mVerboseLoggingEnabled && message.obj != null) log((String) message.obj);
5846                     if (mIpReachabilityDisconnectEnabled) {
5847                         handleIpReachabilityLost();
5848                         transitionTo(mDisconnectingState);
5849                     } else {
5850                         logd("CMD_IP_REACHABILITY_LOST but disconnect disabled -- ignore");
5851                     }
5852                     break;
5853                 case CMD_DISCONNECT:
5854                     mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5855                                 StaEvent.DISCONNECT_UNKNOWN);
5856                     mWifiNative.disconnect();
5857                     transitionTo(mDisconnectingState);
5858                     break;
5859                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5860                     if (message.arg1 == 1) {
5861                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
5862                                 StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
5863                         mWifiNative.disconnect();
5864                         mTemporarilyDisconnectWifi = true;
5865                         transitionTo(mDisconnectingState);
5866                     }
5867                     break;
5868                 case CMD_SET_OPERATIONAL_MODE:
5869                     if (message.arg1 != CONNECT_MODE) {
5870                         sendMessage(CMD_DISCONNECT);
5871                         deferMessage(message);
5872                     }
5873                     break;
5874                     /* Ignore connection to same network */
5875                 case WifiManager.CONNECT_NETWORK:
5876                     int netId = message.arg1;
5877                     if (mWifiInfo.getNetworkId() == netId) {
5878                         replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
5879                         break;
5880                     }
5881                     return NOT_HANDLED;
5882                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5883                     mWifiInfo.setBSSID((String) message.obj);
5884                     mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
5885                     mWifiInfo.setNetworkId(mLastNetworkId);
5886                     if(!mLastBssid.equals(message.obj)) {
5887                         mLastBssid = (String) message.obj;
5888                         sendNetworkStateChangeBroadcast(mLastBssid);
5889                     }
5890                     break;
5891                 case CMD_RSSI_POLL:
5892                     if (message.arg1 == mRssiPollToken) {
5893                         if (mEnableChipWakeUpWhenAssociated) {
5894                             if (mVerboseLoggingEnabled) {
5895                                 log(" get link layer stats " + mWifiLinkLayerStatsSupported);
5896                             }
5897                             WifiLinkLayerStats stats = getWifiLinkLayerStats();
5898                             if (stats != null) {
5899                                 // Sanity check the results provided by driver
5900                                 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
5901                                         && (stats.rssi_mgmt == 0
5902                                         || stats.beacon_rx == 0)) {
5903                                     stats = null;
5904                                 }
5905                             }
5906                             // Get Info and continue polling
5907                             fetchRssiLinkSpeedAndFrequencyNative();
5908                             // Send the update score to network agent.
5909                             mWifiScoreReport.calculateAndReportScore(
5910                                     mWifiInfo, mNetworkAgent, mAggressiveHandover,
5911                                     mWifiMetrics);
5912                         }
5913                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
5914                                 mPollRssiIntervalMsecs);
5915                         if (mVerboseLoggingEnabled) sendRssiChangeBroadcast(mWifiInfo.getRssi());
5916                     } else {
5917                         // Polling has completed
5918                     }
5919                     break;
5920                 case CMD_ENABLE_RSSI_POLL:
5921                     cleanWifiScore();
5922                     if (mEnableRssiPollWhenAssociated) {
5923                         mEnableRssiPolling = (message.arg1 == 1);
5924                     } else {
5925                         mEnableRssiPolling = false;
5926                     }
5927                     mRssiPollToken++;
5928                     if (mEnableRssiPolling) {
5929                         // First poll
5930                         fetchRssiLinkSpeedAndFrequencyNative();
5931                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
5932                                 mPollRssiIntervalMsecs);
5933                     }
5934                     break;
5935                 case WifiManager.RSSI_PKTCNT_FETCH:
5936                     RssiPacketCountInfo info = new RssiPacketCountInfo();
5937                     fetchRssiLinkSpeedAndFrequencyNative();
5938                     info.rssi = mWifiInfo.getRssi();
5939                     WifiNative.TxPacketCounters counters = mWifiNative.getTxPacketCounters();
5940                     if (counters != null) {
5941                         info.txgood = counters.txSucceeded;
5942                         info.txbad = counters.txFailed;
5943                         replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
5944                     } else {
5945                         replyToMessage(message,
5946                                 WifiManager.RSSI_PKTCNT_FETCH_FAILED, WifiManager.ERROR);
5947                     }
5948                     break;
5949                 case CMD_DELAYED_NETWORK_DISCONNECT:
5950                     if (!isLinkDebouncing()) {
5951 
5952                         // Ignore if we are not debouncing
5953                         logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
5954                                 + message.arg1);
5955                         return HANDLED;
5956                     } else {
5957                         logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
5958                                 + message.arg1);
5959 
5960                         mIsLinkDebouncing = false;
5961                         // If we are still debouncing while this message comes,
5962                         // it means we were not able to reconnect within the alloted time
5963                         // = LINK_FLAPPING_DEBOUNCE_MSEC
5964                         // and thus, trigger a real disconnect
5965                         handleNetworkDisconnect();
5966                         transitionTo(mDisconnectedState);
5967                     }
5968                     break;
5969                 case CMD_ASSOCIATED_BSSID:
5970                     if ((String) message.obj == null) {
5971                         logw("Associated command w/o BSSID");
5972                         break;
5973                     }
5974                     mLastBssid = (String) message.obj;
5975                     if (mLastBssid != null && (mWifiInfo.getBSSID() == null
5976                             || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
5977                         mWifiInfo.setBSSID(mLastBssid);
5978                         WifiConfiguration config = getCurrentWifiConfiguration();
5979                         if (config != null) {
5980                             ScanDetailCache scanDetailCache = mWifiConfigManager
5981                                     .getScanDetailCacheForNetwork(config.networkId);
5982                             if (scanDetailCache != null) {
5983                                 ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
5984                                 if (scanResult != null) {
5985                                     mWifiInfo.setFrequency(scanResult.frequency);
5986                                 }
5987                             }
5988                         }
5989                         sendNetworkStateChangeBroadcast(mLastBssid);
5990                     }
5991                     break;
5992                 case CMD_START_RSSI_MONITORING_OFFLOAD:
5993                 case CMD_RSSI_THRESHOLD_BREACHED:
5994                     byte currRssi = (byte) message.arg1;
5995                     processRssiThreshold(currRssi, message.what);
5996                     break;
5997                 case CMD_STOP_RSSI_MONITORING_OFFLOAD:
5998                     stopRssiMonitoringOffload();
5999                     break;
6000                 case CMD_RECONNECT:
6001                     log(" Ignore CMD_RECONNECT request because wifi is already connected");
6002                     break;
6003                 case CMD_RESET_SIM_NETWORKS:
6004                     if (message.arg1 == 0 // sim was removed
6005                             && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6006                         WifiConfiguration config =
6007                                 mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
6008                         if (TelephonyUtil.isSimConfig(config)) {
6009                             mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6010                                     StaEvent.DISCONNECT_RESET_SIM_NETWORKS);
6011                             mWifiNative.disconnect();
6012                             transitionTo(mDisconnectingState);
6013                         }
6014                     }
6015                     /* allow parent state to reset data for other networks */
6016                     return NOT_HANDLED;
6017                 default:
6018                     return NOT_HANDLED;
6019             }
6020 
6021             return HANDLED;
6022         }
6023     }
6024 
6025     class ObtainingIpState extends State {
6026         @Override
enter()6027         public void enter() {
6028             WifiConfiguration currentConfig = getCurrentWifiConfiguration();
6029             boolean isUsingStaticIp =
6030                     (currentConfig.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
6031             if (mVerboseLoggingEnabled) {
6032                 String key = "";
6033                 if (getCurrentWifiConfiguration() != null) {
6034                     key = getCurrentWifiConfiguration().configKey();
6035                 }
6036                 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
6037                         + " " + key + " "
6038                         + " roam=" + mIsAutoRoaming
6039                         + " static=" + isUsingStaticIp);
6040             }
6041 
6042             // Reset link Debouncing, indicating we have successfully re-connected to the AP
6043             // We might still be roaming
6044             mIsLinkDebouncing = false;
6045 
6046             // Send event to CM & network change broadcast
6047             setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
6048 
6049             // We must clear the config BSSID, as the wifi chipset may decide to roam
6050             // from this point on and having the BSSID specified in the network block would
6051             // cause the roam to fail and the device to disconnect.
6052             clearTargetBssid("ObtainingIpAddress");
6053 
6054             // Stop IpManager in case we're switching from DHCP to static
6055             // configuration or vice versa.
6056             //
6057             // TODO: Only ever enter this state the first time we connect to a
6058             // network, never on switching between static configuration and
6059             // DHCP. When we transition from static configuration to DHCP in
6060             // particular, we must tell ConnectivityService that we're
6061             // disconnected, because DHCP might take a long time during which
6062             // connectivity APIs such as getActiveNetworkInfo should not return
6063             // CONNECTED.
6064             stopIpManager();
6065 
6066             mIpManager.setHttpProxy(currentConfig.getHttpProxy());
6067             if (!TextUtils.isEmpty(mTcpBufferSizes)) {
6068                 mIpManager.setTcpBufferSizes(mTcpBufferSizes);
6069             }
6070             final IpManager.ProvisioningConfiguration prov;
6071             if (!isUsingStaticIp) {
6072                 prov = IpManager.buildProvisioningConfiguration()
6073                             .withPreDhcpAction()
6074                             .withApfCapabilities(mWifiNative.getApfCapabilities())
6075                             .build();
6076             } else {
6077                 StaticIpConfiguration staticIpConfig = currentConfig.getStaticIpConfiguration();
6078                 prov = IpManager.buildProvisioningConfiguration()
6079                             .withStaticConfiguration(staticIpConfig)
6080                             .withApfCapabilities(mWifiNative.getApfCapabilities())
6081                             .build();
6082             }
6083             mIpManager.startProvisioning(prov);
6084             // Get Link layer stats so as we get fresh tx packet counters
6085             getWifiLinkLayerStats();
6086         }
6087 
6088         @Override
processMessage(Message message)6089         public boolean processMessage(Message message) {
6090             logStateAndMessage(message, this);
6091 
6092             switch(message.what) {
6093                 case CMD_START_CONNECT:
6094                 case CMD_START_ROAM:
6095                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6096                     break;
6097                 case WifiManager.SAVE_NETWORK:
6098                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6099                     deferMessage(message);
6100                     break;
6101                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6102                     reportConnectionAttemptEnd(
6103                             WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6104                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
6105                     return NOT_HANDLED;
6106                 case CMD_SET_HIGH_PERF_MODE:
6107                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6108                     deferMessage(message);
6109                     break;
6110                     /* Defer scan request since we should not switch to other channels at DHCP */
6111                 case CMD_START_SCAN:
6112                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6113                     deferMessage(message);
6114                     break;
6115                 default:
6116                     return NOT_HANDLED;
6117             }
6118             return HANDLED;
6119         }
6120     }
6121 
6122     /**
6123      * Helper function to check if we need to invoke
6124      * {@link NetworkAgent#explicitlySelected(boolean)} to indicate that we connected to a network
6125      * which the user just chose
6126      * (i.e less than {@link #LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS) before).
6127      */
6128     @VisibleForTesting
shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration currentConfig)6129     public boolean shouldEvaluateWhetherToSendExplicitlySelected(WifiConfiguration currentConfig) {
6130         if (currentConfig == null) {
6131             Log.wtf(TAG, "Current WifiConfiguration is null, but IP provisioning just succeeded");
6132             return false;
6133         }
6134         long currentTimeMillis = mClock.getElapsedSinceBootMillis();
6135         return (mWifiConfigManager.getLastSelectedNetwork() == currentConfig.networkId
6136                 && currentTimeMillis - mWifiConfigManager.getLastSelectedTimeStamp()
6137                 < LAST_SELECTED_NETWORK_EXPIRATION_AGE_MILLIS);
6138     }
6139 
sendConnectedState()6140     private void sendConnectedState() {
6141         // If this network was explicitly selected by the user, evaluate whether to call
6142         // explicitlySelected() so the system can treat it appropriately.
6143         WifiConfiguration config = getCurrentWifiConfiguration();
6144         if (shouldEvaluateWhetherToSendExplicitlySelected(config)) {
6145             boolean prompt =
6146                     mWifiPermissionsUtil.checkNetworkSettingsPermission(config.lastConnectUid);
6147             if (mVerboseLoggingEnabled) {
6148                 log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
6149             }
6150             if (prompt) {
6151                 // Selected by the user via Settings or QuickSettings. If this network has Internet
6152                 // access, switch to it. Otherwise, switch to it only if the user confirms that they
6153                 // really want to switch, or has already confirmed and selected "Don't ask again".
6154                 if (mVerboseLoggingEnabled) {
6155                     log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
6156                 }
6157                 if (mNetworkAgent != null) {
6158                     mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
6159                 }
6160             }
6161         }
6162 
6163         setNetworkDetailedState(DetailedState.CONNECTED);
6164         mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId);
6165         sendNetworkStateChangeBroadcast(mLastBssid);
6166     }
6167 
6168     class RoamingState extends State {
6169         boolean mAssociated;
6170         @Override
enter()6171         public void enter() {
6172             if (mVerboseLoggingEnabled) {
6173                 log("RoamingState Enter"
6174                         + " mScreenOn=" + mScreenOn );
6175             }
6176 
6177             // Make sure we disconnect if roaming fails
6178             roamWatchdogCount++;
6179             logd("Start Roam Watchdog " + roamWatchdogCount);
6180             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
6181                     roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
6182             mAssociated = false;
6183         }
6184         @Override
processMessage(Message message)6185         public boolean processMessage(Message message) {
6186             logStateAndMessage(message, this);
6187             WifiConfiguration config;
6188             switch (message.what) {
6189                 case CMD_IP_CONFIGURATION_LOST:
6190                     config = getCurrentWifiConfiguration();
6191                     if (config != null) {
6192                         mWifiDiagnostics.captureBugReportData(
6193                                 WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
6194                     }
6195                     return NOT_HANDLED;
6196                 case CMD_UNWANTED_NETWORK:
6197                     if (mVerboseLoggingEnabled) {
6198                         log("Roaming and CS doesnt want the network -> ignore");
6199                     }
6200                     return HANDLED;
6201                 case CMD_SET_OPERATIONAL_MODE:
6202                     if (message.arg1 != CONNECT_MODE) {
6203                         deferMessage(message);
6204                     }
6205                     break;
6206                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6207                     /**
6208                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
6209                      * before NETWORK_DISCONNECTION_EVENT
6210                      * And there is an associated BSSID corresponding to our target BSSID, then
6211                      * we have missed the network disconnection, transition to mDisconnectedState
6212                      * and handle the rest of the events there.
6213                      */
6214                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6215                     if (stateChangeResult.state == SupplicantState.DISCONNECTED
6216                             || stateChangeResult.state == SupplicantState.INACTIVE
6217                             || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
6218                         if (mVerboseLoggingEnabled) {
6219                             log("STATE_CHANGE_EVENT in roaming state "
6220                                     + stateChangeResult.toString() );
6221                         }
6222                         if (stateChangeResult.BSSID != null
6223                                 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
6224                             handleNetworkDisconnect();
6225                             transitionTo(mDisconnectedState);
6226                         }
6227                     }
6228                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
6229                         // We completed the layer2 roaming part
6230                         mAssociated = true;
6231                         if (stateChangeResult.BSSID != null) {
6232                             mTargetRoamBSSID = stateChangeResult.BSSID;
6233                         }
6234                     }
6235                     break;
6236                 case CMD_ROAM_WATCHDOG_TIMER:
6237                     if (roamWatchdogCount == message.arg1) {
6238                         if (mVerboseLoggingEnabled) log("roaming watchdog! -> disconnect");
6239                         mWifiMetrics.endConnectionEvent(
6240                                 WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
6241                                 WifiMetricsProto.ConnectionEvent.HLF_NONE);
6242                         mRoamFailCount++;
6243                         handleNetworkDisconnect();
6244                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6245                                 StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER);
6246                         mWifiNative.disconnect();
6247                         transitionTo(mDisconnectedState);
6248                     }
6249                     break;
6250                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
6251                     if (mAssociated) {
6252                         if (mVerboseLoggingEnabled) {
6253                             log("roaming and Network connection established");
6254                         }
6255                         mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
6256                         mLastBssid = (String) message.obj;
6257                         mWifiInfo.setBSSID(mLastBssid);
6258                         mWifiInfo.setNetworkId(mLastNetworkId);
6259                         int reasonCode = message.arg2;
6260                         mWifiConnectivityManager.trackBssid(mLastBssid, true, reasonCode);
6261                         sendNetworkStateChangeBroadcast(mLastBssid);
6262 
6263                         // Successful framework roam! (probably)
6264                         reportConnectionAttemptEnd(
6265                                 WifiMetrics.ConnectionEvent.FAILURE_NONE,
6266                                 WifiMetricsProto.ConnectionEvent.HLF_NONE);
6267 
6268                         // We must clear the config BSSID, as the wifi chipset may decide to roam
6269                         // from this point on and having the BSSID specified by QNS would cause
6270                         // the roam to fail and the device to disconnect.
6271                         // When transition from RoamingState to DisconnectingState or
6272                         // DisconnectedState, the config BSSID is cleared by
6273                         // handleNetworkDisconnect().
6274                         clearTargetBssid("RoamingCompleted");
6275 
6276                         // We used to transition to ObtainingIpState in an
6277                         // attempt to do DHCPv4 RENEWs on framework roams.
6278                         // DHCP can take too long to time out, and we now rely
6279                         // upon IpManager's use of IpReachabilityMonitor to
6280                         // confirm our current network configuration.
6281                         //
6282                         // mIpManager.confirmConfiguration() is called within
6283                         // the handling of SupplicantState.COMPLETED.
6284                         transitionTo(mConnectedState);
6285                     } else {
6286                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6287                     }
6288                     break;
6289                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6290                     // Throw away but only if it corresponds to the network we're roaming to
6291                     String bssid = (String) message.obj;
6292                     if (true) {
6293                         String target = "";
6294                         if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
6295                         log("NETWORK_DISCONNECTION_EVENT in roaming state"
6296                                 + " BSSID=" + bssid
6297                                 + " target=" + target);
6298                     }
6299                     if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
6300                         handleNetworkDisconnect();
6301                         transitionTo(mDisconnectedState);
6302                     }
6303                     break;
6304                 case CMD_START_SCAN:
6305                     deferMessage(message);
6306                     break;
6307                 default:
6308                     return NOT_HANDLED;
6309             }
6310             return HANDLED;
6311         }
6312 
6313         @Override
exit()6314         public void exit() {
6315             logd("WifiStateMachine: Leaving Roaming state");
6316         }
6317     }
6318 
6319     class ConnectedState extends State {
6320         @Override
enter()6321         public void enter() {
6322             // TODO: b/64349637 Investigate getting default router IP/MAC address info from
6323             // IpManager
6324             //updateDefaultRouteMacAddress(1000);
6325             if (mVerboseLoggingEnabled) {
6326                 log("Enter ConnectedState "
6327                        + " mScreenOn=" + mScreenOn);
6328             }
6329 
6330             mWifiConnectivityManager.handleConnectionStateChanged(
6331                     WifiConnectivityManager.WIFI_STATE_CONNECTED);
6332             registerConnected();
6333             lastConnectAttemptTimestamp = 0;
6334             targetWificonfiguration = null;
6335             // Paranoia
6336             mIsLinkDebouncing = false;
6337 
6338             // Not roaming anymore
6339             mIsAutoRoaming = false;
6340 
6341             if (testNetworkDisconnect) {
6342                 testNetworkDisconnectCounter++;
6343                 logd("ConnectedState Enter start disconnect test " +
6344                         testNetworkDisconnectCounter);
6345                 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
6346                         testNetworkDisconnectCounter, 0), 15000);
6347             }
6348 
6349             mLastDriverRoamAttempt = 0;
6350             mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
6351             mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
6352             mWifiStateTracker.updateState(WifiStateTracker.CONNECTED);
6353         }
6354         @Override
processMessage(Message message)6355         public boolean processMessage(Message message) {
6356             WifiConfiguration config = null;
6357             logStateAndMessage(message, this);
6358 
6359             switch (message.what) {
6360                 case CMD_UNWANTED_NETWORK:
6361                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
6362                         mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6363                                 StaEvent.DISCONNECT_UNWANTED);
6364                         mWifiNative.disconnect();
6365                         transitionTo(mDisconnectingState);
6366                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
6367                             message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
6368                         Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
6369                                 ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
6370                                 : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
6371                         config = getCurrentWifiConfiguration();
6372                         if (config != null) {
6373                             // Disable autojoin
6374                             if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
6375                                 mWifiConfigManager.setNetworkValidatedInternetAccess(
6376                                         config.networkId, false);
6377                                 mWifiConfigManager.updateNetworkSelectionStatus(config.networkId,
6378                                         WifiConfiguration.NetworkSelectionStatus
6379                                         .DISABLED_NO_INTERNET);
6380                             }
6381                             mWifiConfigManager.incrementNetworkNoInternetAccessReports(
6382                                     config.networkId);
6383                         }
6384                     }
6385                     return HANDLED;
6386                 case CMD_NETWORK_STATUS:
6387                     if (message.arg1 == NetworkAgent.VALID_NETWORK) {
6388                         config = getCurrentWifiConfiguration();
6389                         if (config != null) {
6390                             // re-enable autojoin
6391                             mWifiConfigManager.setNetworkValidatedInternetAccess(
6392                                     config.networkId, true);
6393                         }
6394                     }
6395                     return HANDLED;
6396                 case CMD_ACCEPT_UNVALIDATED:
6397                     boolean accept = (message.arg1 != 0);
6398                     mWifiConfigManager.setNetworkNoInternetAccessExpected(mLastNetworkId, accept);
6399                     return HANDLED;
6400                 case CMD_TEST_NETWORK_DISCONNECT:
6401                     // Force a disconnect
6402                     if (message.arg1 == testNetworkDisconnectCounter) {
6403                         mWifiNative.disconnect();
6404                     }
6405                     break;
6406                 case CMD_ASSOCIATED_BSSID:
6407                     // ASSOCIATING to a new BSSID while already connected, indicates
6408                     // that driver is roaming
6409                     mLastDriverRoamAttempt = mClock.getWallClockMillis();
6410                     return NOT_HANDLED;
6411                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6412                     long lastRoam = 0;
6413                     reportConnectionAttemptEnd(
6414                             WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6415                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
6416                     if (mLastDriverRoamAttempt != 0) {
6417                         // Calculate time since last driver roam attempt
6418                         lastRoam = mClock.getWallClockMillis() - mLastDriverRoamAttempt;
6419                         mLastDriverRoamAttempt = 0;
6420                     }
6421                     if (unexpectedDisconnectedReason(message.arg2)) {
6422                         mWifiDiagnostics.captureBugReportData(
6423                                 WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
6424                     }
6425                     config = getCurrentWifiConfiguration();
6426                     if (mEnableLinkDebouncing
6427                             && mScreenOn
6428                             && !isLinkDebouncing()
6429                             && config != null
6430                             && config.getNetworkSelectionStatus().isNetworkEnabled()
6431                             && config.networkId != mWifiConfigManager.getLastSelectedNetwork()
6432                             && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
6433                                 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
6434                             && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
6435                                     && mWifiInfo.getRssi() >
6436                                      mThresholdQualifiedRssi5)
6437                                     || (ScanResult.is5GHz(mWifiInfo.getFrequency())
6438                                     && mWifiInfo.getRssi() >
6439                                     mThresholdQualifiedRssi5))) {
6440                         // Start de-bouncing the L2 disconnection:
6441                         // this L2 disconnection might be spurious.
6442                         // Hence we allow 4 seconds for the state machine to try
6443                         // to reconnect, go thru the
6444                         // roaming cycle and enter Obtaining IP address
6445                         // before signalling the disconnect to ConnectivityService and L3
6446                         startScanForConfiguration(getCurrentWifiConfiguration());
6447                         mIsLinkDebouncing = true;
6448 
6449                         sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
6450                                 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
6451                         if (mVerboseLoggingEnabled) {
6452                             log("NETWORK_DISCONNECTION_EVENT in connected state"
6453                                     + " BSSID=" + mWifiInfo.getBSSID()
6454                                     + " RSSI=" + mWifiInfo.getRssi()
6455                                     + " freq=" + mWifiInfo.getFrequency()
6456                                     + " reason=" + message.arg2
6457                                     + " -> debounce");
6458                         }
6459                         return HANDLED;
6460                     } else {
6461                         if (mVerboseLoggingEnabled) {
6462                             log("NETWORK_DISCONNECTION_EVENT in connected state"
6463                                     + " BSSID=" + mWifiInfo.getBSSID()
6464                                     + " RSSI=" + mWifiInfo.getRssi()
6465                                     + " freq=" + mWifiInfo.getFrequency()
6466                                     + " was debouncing=" + isLinkDebouncing()
6467                                     + " reason=" + message.arg2
6468                                     + " Network Selection Status=" + (config == null ? "Unavailable"
6469                                     : config.getNetworkSelectionStatus().getNetworkStatusString()));
6470                         }
6471                     }
6472                     break;
6473                 case CMD_START_ROAM:
6474                     // Clear the driver roam indication since we are attempting a framework roam
6475                     mLastDriverRoamAttempt = 0;
6476 
6477                     /* Connect command coming from auto-join */
6478                     int netId = message.arg1;
6479                     ScanResult candidate = (ScanResult)message.obj;
6480                     String bssid = SUPPLICANT_BSSID_ANY;
6481                     if (candidate != null) {
6482                         bssid = candidate.BSSID;
6483                     }
6484                     config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
6485                     if (config == null) {
6486                         loge("CMD_START_ROAM and no config, bail out...");
6487                         break;
6488                     }
6489 
6490                     setTargetBssid(config, bssid);
6491                     mTargetNetworkId = netId;
6492 
6493                     logd("CMD_START_ROAM sup state "
6494                             + mSupplicantStateTracker.getSupplicantStateName()
6495                             + " my state " + getCurrentState().getName()
6496                             + " nid=" + Integer.toString(netId)
6497                             + " config " + config.configKey()
6498                             + " targetRoamBSSID " + mTargetRoamBSSID);
6499 
6500                     reportConnectionAttemptStart(config, mTargetRoamBSSID,
6501                             WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
6502                     if (mWifiNative.roamToNetwork(config)) {
6503                         lastConnectAttemptTimestamp = mClock.getWallClockMillis();
6504                         targetWificonfiguration = config;
6505                         mIsAutoRoaming = true;
6506                         mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_ROAM, config);
6507                         transitionTo(mRoamingState);
6508                     } else {
6509                         loge("CMD_START_ROAM Failed to start roaming to network " + config);
6510                         reportConnectionAttemptEnd(
6511                                 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6512                                 WifiMetricsProto.ConnectionEvent.HLF_NONE);
6513                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6514                                 WifiManager.ERROR);
6515                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6516                         break;
6517                     }
6518                     break;
6519                 case CMD_START_IP_PACKET_OFFLOAD: {
6520                     int slot = message.arg1;
6521                     int intervalSeconds = message.arg2;
6522                     KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
6523                     byte[] dstMac;
6524                     try {
6525                         InetAddress gateway = RouteInfo.selectBestRoute(
6526                                 mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
6527                         String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
6528                         dstMac = NativeUtil.macAddressToByteArray(dstMacStr);
6529                     } catch (NullPointerException | IllegalArgumentException e) {
6530                         loge("Can't find MAC address for next hop to " + pkt.dstAddress);
6531                         if (mNetworkAgent != null) {
6532                             mNetworkAgent.onPacketKeepaliveEvent(slot,
6533                                     ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
6534                         }
6535                         break;
6536                     }
6537                     pkt.dstMac = dstMac;
6538                     int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
6539                     if (mNetworkAgent != null) {
6540                         mNetworkAgent.onPacketKeepaliveEvent(slot, result);
6541                     }
6542                     break;
6543                 }
6544                 default:
6545                     return NOT_HANDLED;
6546             }
6547             return HANDLED;
6548         }
6549 
6550         @Override
exit()6551         public void exit() {
6552             logd("WifiStateMachine: Leaving Connected state");
6553             mWifiConnectivityManager.handleConnectionStateChanged(
6554                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
6555 
6556             mLastDriverRoamAttempt = 0;
6557             mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
6558         }
6559     }
6560 
6561     class DisconnectingState extends State {
6562 
6563         @Override
enter()6564         public void enter() {
6565 
6566             if (mVerboseLoggingEnabled) {
6567                 logd(" Enter DisconnectingState State screenOn=" + mScreenOn);
6568             }
6569 
6570             // Make sure we disconnect: we enter this state prior to connecting to a new
6571             // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
6572             // event which in this case will be indicating that supplicant started to associate.
6573             // In some cases supplicant doesn't ignore the connect requests (it might not
6574             // find the target SSID in its cache),
6575             // Therefore we end up stuck that state, hence the need for the watchdog.
6576             disconnectingWatchdogCount++;
6577             logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
6578             sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
6579                     disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
6580         }
6581 
6582         @Override
processMessage(Message message)6583         public boolean processMessage(Message message) {
6584             logStateAndMessage(message, this);
6585             switch (message.what) {
6586                 case CMD_SET_OPERATIONAL_MODE:
6587                     if (message.arg1 != CONNECT_MODE) {
6588                         deferMessage(message);
6589                     }
6590                     break;
6591                 case CMD_START_SCAN:
6592                     deferMessage(message);
6593                     return HANDLED;
6594                 case CMD_DISCONNECT:
6595                     if (mVerboseLoggingEnabled) log("Ignore CMD_DISCONNECT when already disconnecting.");
6596                     break;
6597                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
6598                     if (disconnectingWatchdogCount == message.arg1) {
6599                         if (mVerboseLoggingEnabled) log("disconnecting watchdog! -> disconnect");
6600                         handleNetworkDisconnect();
6601                         transitionTo(mDisconnectedState);
6602                     }
6603                     break;
6604                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6605                     /**
6606                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
6607                      * we have missed the network disconnection, transition to mDisconnectedState
6608                      * and handle the rest of the events there
6609                      */
6610                     deferMessage(message);
6611                     handleNetworkDisconnect();
6612                     transitionTo(mDisconnectedState);
6613                     break;
6614                 default:
6615                     return NOT_HANDLED;
6616             }
6617             return HANDLED;
6618         }
6619     }
6620 
6621     class DisconnectedState extends State {
6622         @Override
enter()6623         public void enter() {
6624             Log.i(TAG, "disconnectedstate enter");
6625             // We dont scan frequently if this is a temporary disconnect
6626             // due to p2p
6627             if (mTemporarilyDisconnectWifi) {
6628                 p2pSendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
6629                 return;
6630             }
6631 
6632             if (mVerboseLoggingEnabled) {
6633                 logd(" Enter DisconnectedState screenOn=" + mScreenOn);
6634             }
6635 
6636             /** clear the roaming state, if we were roaming, we failed */
6637             mIsAutoRoaming = false;
6638 
6639             mWifiConnectivityManager.handleConnectionStateChanged(
6640                     WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
6641 
6642             /**
6643              * If we have no networks saved, the supplicant stops doing the periodic scan.
6644              * The scans are useful to notify the user of the presence of an open network.
6645              * Note that these are not wake up scans.
6646              */
6647             if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
6648                     && mWifiConfigManager.getSavedNetworks().size() == 0) {
6649                 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6650                         ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6651             }
6652 
6653             mDisconnectedTimeStamp = mClock.getWallClockMillis();
6654             mWifiStateTracker.updateState(WifiStateTracker.DISCONNECTED);
6655         }
6656         @Override
processMessage(Message message)6657         public boolean processMessage(Message message) {
6658             boolean ret = HANDLED;
6659 
6660             logStateAndMessage(message, this);
6661 
6662             switch (message.what) {
6663                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
6664                     if (mP2pConnected.get()) break;
6665                     if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
6666                             mWifiConfigManager.getSavedNetworks().size() == 0) {
6667                         startScan(UNKNOWN_SCAN_SOURCE, -1, null, WIFI_WORK_SOURCE);
6668                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6669                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6670                     }
6671                     break;
6672                 case WifiManager.FORGET_NETWORK:
6673                 case CMD_REMOVE_NETWORK:
6674                 case CMD_REMOVE_APP_CONFIGURATIONS:
6675                 case CMD_REMOVE_USER_CONFIGURATIONS:
6676                     // Set up a delayed message here. After the forget/remove is handled
6677                     // the handled delayed message will determine if there is a need to
6678                     // scan and continue
6679                     sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6680                                 ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6681                     ret = NOT_HANDLED;
6682                     break;
6683                 case CMD_SET_OPERATIONAL_MODE:
6684                     if (message.arg1 != CONNECT_MODE) {
6685                         mOperationalMode = message.arg1;
6686                         if (mOperationalMode == DISABLED_MODE) {
6687                             transitionTo(mSupplicantStoppingState);
6688                         } else if (mOperationalMode == SCAN_ONLY_MODE
6689                                 || mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6690                             p2pSendMessage(CMD_DISABLE_P2P_REQ);
6691                             setWifiState(WIFI_STATE_DISABLED);
6692                             transitionTo(mScanModeState);
6693                         }
6694                     }
6695                     break;
6696                 case CMD_DISCONNECT:
6697                     mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
6698                             StaEvent.DISCONNECT_UNKNOWN);
6699                     mWifiNative.disconnect();
6700                     break;
6701                 /* Ignore network disconnect */
6702                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6703                     // Interpret this as an L2 connection failure
6704                     break;
6705                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6706                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6707                     if (mVerboseLoggingEnabled) {
6708                         logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
6709                                 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
6710                                 + " debouncing=" + isLinkDebouncing());
6711                     }
6712                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
6713                     /* ConnectModeState does the rest of the handling */
6714                     ret = NOT_HANDLED;
6715                     break;
6716                 case CMD_START_SCAN:
6717                     if (!checkOrDeferScanAllowed(message)) {
6718                         // The scan request was rescheduled
6719                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
6720                         return HANDLED;
6721                     }
6722 
6723                     ret = NOT_HANDLED;
6724                     break;
6725                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
6726                     NetworkInfo info = (NetworkInfo) message.obj;
6727                     mP2pConnected.set(info.isConnected());
6728                     if (!mP2pConnected.get() && mWifiConfigManager.getSavedNetworks().size() == 0) {
6729                         if (mVerboseLoggingEnabled) log("Turn on scanning after p2p disconnected");
6730                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6731                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6732                     }
6733                     break;
6734                 case CMD_RECONNECT:
6735                 case CMD_REASSOCIATE:
6736                     if (mTemporarilyDisconnectWifi) {
6737                         // Drop a third party reconnect/reassociate if STA is
6738                         // temporarily disconnected for p2p
6739                         break;
6740                     } else {
6741                         // ConnectModeState handles it
6742                         ret = NOT_HANDLED;
6743                     }
6744                     break;
6745                 case CMD_SCREEN_STATE_CHANGED:
6746                     handleScreenStateChanged(message.arg1 != 0);
6747                     break;
6748                 default:
6749                     ret = NOT_HANDLED;
6750             }
6751             return ret;
6752         }
6753 
6754         @Override
exit()6755         public void exit() {
6756             mWifiConnectivityManager.handleConnectionStateChanged(
6757                      WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
6758         }
6759     }
6760 
6761     /**
6762      * WPS connection flow:
6763      * 1. WifiStateMachine receive WPS_START message from WifiManager API.
6764      * 2. WifiStateMachine initiates the appropriate WPS operation using WifiNative methods:
6765      * {@link WifiNative#startWpsPbc(String)}, {@link WifiNative#startWpsPinDisplay(String)}, etc.
6766      * 3. WifiStateMachine then transitions to this WpsRunningState.
6767      * 4a. Once WifiStateMachine receive the connected event:
6768      * {@link WifiMonitor#NETWORK_CONNECTION_EVENT},
6769      * 4a.1 Load the network params out of wpa_supplicant.
6770      * 4a.2 Add the network with params to WifiConfigManager.
6771      * 4a.3 Enable the network with |disableOthers| set to true.
6772      * 4a.4 Send a response to the original source of WifiManager API using {@link #mSourceMessage}.
6773      * 4b. Any failures are notified to the original source of WifiManager API
6774      * using {@link #mSourceMessage}.
6775      * 5. We then transition to disconnected state and let network selection reconnect to the newly
6776      * added network.
6777      */
6778     class WpsRunningState extends State {
6779         // Tracks the source to provide a reply
6780         private Message mSourceMessage;
6781         @Override
enter()6782         public void enter() {
6783             mSourceMessage = Message.obtain(getCurrentMessage());
6784         }
6785         @Override
processMessage(Message message)6786         public boolean processMessage(Message message) {
6787             logStateAndMessage(message, this);
6788 
6789             switch (message.what) {
6790                 case WifiMonitor.WPS_SUCCESS_EVENT:
6791                     // Ignore intermediate success, wait for full connection
6792                     break;
6793                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
6794                     Pair<Boolean, Integer> loadResult = loadNetworksFromSupplicantAfterWps();
6795                     boolean success = loadResult.first;
6796                     int netId = loadResult.second;
6797                     if (success) {
6798                         message.arg1 = netId;
6799                         replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
6800                     } else {
6801                         replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
6802                                 WifiManager.ERROR);
6803                     }
6804                     mSourceMessage.recycle();
6805                     mSourceMessage = null;
6806                     deferMessage(message);
6807                     transitionTo(mDisconnectedState);
6808                     break;
6809                 case WifiMonitor.WPS_OVERLAP_EVENT:
6810                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
6811                             WifiManager.WPS_OVERLAP_ERROR);
6812                     mSourceMessage.recycle();
6813                     mSourceMessage = null;
6814                     transitionTo(mDisconnectedState);
6815                     break;
6816                 case WifiMonitor.WPS_FAIL_EVENT:
6817                     // Arg1 has the reason for the failure
6818                     if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
6819                         replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
6820                         mSourceMessage.recycle();
6821                         mSourceMessage = null;
6822                         transitionTo(mDisconnectedState);
6823                     } else {
6824                         if (mVerboseLoggingEnabled) {
6825                             log("Ignore unspecified fail event during WPS connection");
6826                         }
6827                     }
6828                     break;
6829                 case WifiMonitor.WPS_TIMEOUT_EVENT:
6830                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
6831                             WifiManager.WPS_TIMED_OUT);
6832                     mSourceMessage.recycle();
6833                     mSourceMessage = null;
6834                     transitionTo(mDisconnectedState);
6835                     break;
6836                 case WifiManager.START_WPS:
6837                     replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
6838                     break;
6839                 case WifiManager.CANCEL_WPS:
6840                     if (mWifiNative.cancelWps()) {
6841                         replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
6842                     } else {
6843                         replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
6844                     }
6845                     transitionTo(mDisconnectedState);
6846                     break;
6847                 /**
6848                  * Defer all commands that can cause connections to a different network
6849                  * or put the state machine out of connect mode
6850                  */
6851                 case CMD_SET_OPERATIONAL_MODE:
6852                 case WifiManager.CONNECT_NETWORK:
6853                 case CMD_ENABLE_NETWORK:
6854                 case CMD_RECONNECT:
6855                     log(" Ignore CMD_RECONNECT request because wps is running");
6856                     return HANDLED;
6857                 case CMD_REASSOCIATE:
6858                     deferMessage(message);
6859                     break;
6860                 case CMD_START_CONNECT:
6861                 case CMD_START_ROAM:
6862                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6863                     return HANDLED;
6864                 case CMD_START_SCAN:
6865                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6866                     return HANDLED;
6867                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6868                     if (mVerboseLoggingEnabled) log("Network connection lost");
6869                     handleNetworkDisconnect();
6870                     break;
6871                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6872                     if (mVerboseLoggingEnabled) {
6873                         log("Ignore Assoc reject event during WPS Connection");
6874                     }
6875                     break;
6876                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6877                     // Disregard auth failure events during WPS connection. The
6878                     // EAP sequence is retried several times, and there might be
6879                     // failures (especially for wps pin). We will get a WPS_XXX
6880                     // event at the end of the sequence anyway.
6881                     if (mVerboseLoggingEnabled) log("Ignore auth failure during WPS connection");
6882                     break;
6883                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6884                     // Throw away supplicant state changes when WPS is running.
6885                     // We will start getting supplicant state changes once we get
6886                     // a WPS success or failure
6887                     break;
6888                 default:
6889                     return NOT_HANDLED;
6890             }
6891             return HANDLED;
6892         }
6893 
6894         /**
6895          * Load network config from wpa_supplicant after WPS is complete.
6896          * @return a boolean (true if load was successful) and integer (Network Id of currently
6897          *          connected network, can be {@link WifiConfiguration#INVALID_NETWORK_ID} despite
6898          *          successful loading, if multiple networks in supplicant) pair.
6899          */
loadNetworksFromSupplicantAfterWps()6900         private Pair<Boolean, Integer> loadNetworksFromSupplicantAfterWps() {
6901             Map<String, WifiConfiguration> configs = new HashMap<>();
6902             SparseArray<Map<String, String>> extras = new SparseArray<>();
6903             int netId = WifiConfiguration.INVALID_NETWORK_ID;
6904             if (!mWifiNative.migrateNetworksFromSupplicant(configs, extras)) {
6905                 loge("Failed to load networks from wpa_supplicant after Wps");
6906                 return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
6907             }
6908             for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) {
6909                 WifiConfiguration config = entry.getValue();
6910                 // Reset the network ID retrieved from wpa_supplicant, since we want to treat
6911                 // this as a new network addition in framework.
6912                 config.networkId = WifiConfiguration.INVALID_NETWORK_ID;
6913                 NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(
6914                         config, mSourceMessage.sendingUid);
6915                 if (!result.isSuccess()) {
6916                     loge("Failed to add network after WPS: " + entry.getValue());
6917                     return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
6918                 }
6919                 if (!mWifiConfigManager.enableNetwork(
6920                         result.getNetworkId(), true, mSourceMessage.sendingUid)) {
6921                     Log.wtf(TAG, "Failed to enable network after WPS: " + entry.getValue());
6922                     return Pair.create(false, WifiConfiguration.INVALID_NETWORK_ID);
6923                 }
6924                 netId = result.getNetworkId();
6925             }
6926             return Pair.create(true,
6927                     configs.size() == 1 ? netId : WifiConfiguration.INVALID_NETWORK_ID);
6928         }
6929     }
6930 
6931     class SoftApState extends State {
6932         private SoftApManager mSoftApManager;
6933         private String mIfaceName;
6934         private int mMode;
6935 
6936         private class SoftApListener implements SoftApManager.Listener {
6937             @Override
onStateChanged(int state, int reason)6938             public void onStateChanged(int state, int reason) {
6939                 if (state == WIFI_AP_STATE_DISABLED) {
6940                     sendMessage(CMD_AP_STOPPED);
6941                 } else if (state == WIFI_AP_STATE_FAILED) {
6942                     sendMessage(CMD_START_AP_FAILURE);
6943                 }
6944 
6945                 setWifiApState(state, reason, mIfaceName, mMode);
6946             }
6947         }
6948 
6949         @Override
enter()6950         public void enter() {
6951             final Message message = getCurrentMessage();
6952             if (message.what != CMD_START_AP) {
6953                 throw new RuntimeException("Illegal transition to SoftApState: " + message);
6954             }
6955             SoftApModeConfiguration config = (SoftApModeConfiguration) message.obj;
6956             mMode = config.getTargetMode();
6957 
6958             IApInterface apInterface = null;
6959             Pair<Integer, IApInterface> statusAndInterface = mWifiNative.setupForSoftApMode();
6960             if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
6961                 apInterface = statusAndInterface.second;
6962             } else {
6963                 incrementMetricsForSetupFailure(statusAndInterface.first);
6964             }
6965             if (apInterface == null) {
6966                 setWifiApState(WIFI_AP_STATE_FAILED,
6967                         WifiManager.SAP_START_FAILURE_GENERAL, null, mMode);
6968                 /**
6969                  * Transition to InitialState to reset the
6970                  * driver/HAL back to the initial state.
6971                  */
6972                 transitionTo(mInitialState);
6973                 return;
6974             }
6975 
6976             try {
6977                 mIfaceName = apInterface.getInterfaceName();
6978             } catch (RemoteException e) {
6979                 // Failed to get the interface name. The name will not be available for
6980                 // the enabled broadcast, but since we had an error getting the name, we most likely
6981                 // won't be able to fully start softap mode.
6982             }
6983 
6984             checkAndSetConnectivityInstance();
6985             mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
6986                                                              new SoftApListener(),
6987                                                              apInterface,
6988                                                              config.getWifiConfiguration());
6989             mSoftApManager.start();
6990             mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
6991         }
6992 
6993         @Override
exit()6994         public void exit() {
6995             mSoftApManager = null;
6996             mIfaceName = null;
6997             mMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
6998         }
6999 
7000         @Override
processMessage(Message message)7001         public boolean processMessage(Message message) {
7002             logStateAndMessage(message, this);
7003 
7004             switch(message.what) {
7005                 case CMD_START_AP:
7006                     /* Ignore start command when it is starting/started. */
7007                     break;
7008                 case CMD_STOP_AP:
7009                     mSoftApManager.stop();
7010                     break;
7011                 case CMD_START_AP_FAILURE:
7012                     transitionTo(mInitialState);
7013                     break;
7014                 case CMD_AP_STOPPED:
7015                     transitionTo(mInitialState);
7016                     break;
7017                 default:
7018                     return NOT_HANDLED;
7019             }
7020             return HANDLED;
7021         }
7022     }
7023 
7024     /**
7025      * State machine initiated requests can have replyTo set to null indicating
7026      * there are no recepients, we ignore those reply actions.
7027      */
replyToMessage(Message msg, int what)7028     private void replyToMessage(Message msg, int what) {
7029         if (msg.replyTo == null) return;
7030         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7031         mReplyChannel.replyToMessage(msg, dstMsg);
7032     }
7033 
replyToMessage(Message msg, int what, int arg1)7034     private void replyToMessage(Message msg, int what, int arg1) {
7035         if (msg.replyTo == null) return;
7036         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7037         dstMsg.arg1 = arg1;
7038         mReplyChannel.replyToMessage(msg, dstMsg);
7039     }
7040 
replyToMessage(Message msg, int what, Object obj)7041     private void replyToMessage(Message msg, int what, Object obj) {
7042         if (msg.replyTo == null) return;
7043         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7044         dstMsg.obj = obj;
7045         mReplyChannel.replyToMessage(msg, dstMsg);
7046     }
7047 
7048     /**
7049      * arg2 on the source message has a unique id that needs to be retained in replies
7050      * to match the request
7051      * <p>see WifiManager for details
7052      */
obtainMessageWithWhatAndArg2(Message srcMsg, int what)7053     private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
7054         Message msg = Message.obtain();
7055         msg.what = what;
7056         msg.arg2 = srcMsg.arg2;
7057         return msg;
7058     }
7059 
7060     /**
7061      * Notify interested parties if a wifi config has been changed.
7062      *
7063      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
7064      * @param config Must have a WifiConfiguration object to succeed
7065      * TODO: b/35258354 investigate if this can be removed.  Is the broadcast sent by
7066      * WifiConfigManager sufficient?
7067      */
broadcastWifiCredentialChanged(int wifiCredentialEventType, WifiConfiguration config)7068     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
7069             WifiConfiguration config) {
7070         if (config != null && config.preSharedKey != null) {
7071             Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
7072             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
7073             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
7074                     wifiCredentialEventType);
7075             mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
7076                     android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
7077         }
7078     }
7079 
handleGsmAuthRequest(SimAuthRequestData requestData)7080     void handleGsmAuthRequest(SimAuthRequestData requestData) {
7081         if (targetWificonfiguration == null
7082                 || targetWificonfiguration.networkId
7083                 == lookupFrameworkNetworkId(requestData.networkId)) {
7084             logd("id matches targetWifiConfiguration");
7085         } else {
7086             logd("id does not match targetWifiConfiguration");
7087             return;
7088         }
7089 
7090         String response =
7091                 TelephonyUtil.getGsmSimAuthResponse(requestData.data, getTelephonyManager());
7092         if (response == null) {
7093             mWifiNative.simAuthFailedResponse(requestData.networkId);
7094         } else {
7095             logv("Supplicant Response -" + response);
7096             mWifiNative.simAuthResponse(requestData.networkId,
7097                     WifiNative.SIM_AUTH_RESP_TYPE_GSM_AUTH, response);
7098         }
7099     }
7100 
handle3GAuthRequest(SimAuthRequestData requestData)7101     void handle3GAuthRequest(SimAuthRequestData requestData) {
7102         if (targetWificonfiguration == null
7103                 || targetWificonfiguration.networkId
7104                 == lookupFrameworkNetworkId(requestData.networkId)) {
7105             logd("id matches targetWifiConfiguration");
7106         } else {
7107             logd("id does not match targetWifiConfiguration");
7108             return;
7109         }
7110 
7111         SimAuthResponseData response =
7112                 TelephonyUtil.get3GAuthResponse(requestData, getTelephonyManager());
7113         if (response != null) {
7114             mWifiNative.simAuthResponse(requestData.networkId, response.type, response.response);
7115         } else {
7116             mWifiNative.umtsAuthFailedResponse(requestData.networkId);
7117         }
7118     }
7119 
7120     /**
7121      * Automatically connect to the network specified
7122      *
7123      * @param networkId ID of the network to connect to
7124      * @param uid UID of the app triggering the connection.
7125      * @param bssid BSSID of the network
7126      */
startConnectToNetwork(int networkId, int uid, String bssid)7127     public void startConnectToNetwork(int networkId, int uid, String bssid) {
7128         sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
7129     }
7130 
7131     /**
7132      * Automatically roam to the network specified
7133      *
7134      * @param networkId ID of the network to roam to
7135      * @param scanResult scan result which identifies the network to roam to
7136      */
startRoamToNetwork(int networkId, ScanResult scanResult)7137     public void startRoamToNetwork(int networkId, ScanResult scanResult) {
7138         sendMessage(CMD_START_ROAM, networkId, 0, scanResult);
7139     }
7140 
7141     /**
7142      * Dynamically turn on/off WifiConnectivityManager
7143      *
7144      * @param enabled true-enable; false-disable
7145      */
enableWifiConnectivityManager(boolean enabled)7146     public void enableWifiConnectivityManager(boolean enabled) {
7147         sendMessage(CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER, enabled ? 1 : 0);
7148     }
7149 
7150     /**
7151      * @param reason reason code from supplicant on network disconnected event
7152      * @return true if this is a suspicious disconnect
7153      */
unexpectedDisconnectedReason(int reason)7154     static boolean unexpectedDisconnectedReason(int reason) {
7155         return reason == 2              // PREV_AUTH_NOT_VALID
7156                 || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
7157                 || reason == 7          // FRAME_FROM_NONASSOC_STA
7158                 || reason == 8          // STA_HAS_LEFT
7159                 || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
7160                 || reason == 14         // MICHAEL_MIC_FAILURE
7161                 || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
7162                 || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
7163                 || reason == 18         // GROUP_CIPHER_NOT_VALID
7164                 || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
7165                 || reason == 23         // IEEE_802_1X_AUTH_FAILED
7166                 || reason == 34;        // DISASSOC_LOW_ACK
7167     }
7168 
7169     /**
7170      * Update WifiMetrics before dumping
7171      */
updateWifiMetrics()7172     public void updateWifiMetrics() {
7173         mWifiMetrics.updateSavedNetworks(mWifiConfigManager.getSavedNetworks());
7174         mPasspointManager.updateMetrics();
7175     }
7176 
7177     /**
7178      * Private method to handle calling WifiConfigManager to forget/remove network configs and reply
7179      * to the message from the sender of the outcome.
7180      *
7181      * The current implementation requires that forget and remove be handled in different ways
7182      * (responses are handled differently).  In the interests of organization, the handling is all
7183      * now in this helper method.  TODO: b/35257965 is filed to track the possibility of merging
7184      * the two call paths.
7185      */
deleteNetworkConfigAndSendReply(Message message, boolean calledFromForget)7186     private boolean deleteNetworkConfigAndSendReply(Message message, boolean calledFromForget) {
7187         boolean success = mWifiConfigManager.removeNetwork(message.arg1, message.sendingUid);
7188         if (!success) {
7189             loge("Failed to remove network");
7190         }
7191 
7192         if (calledFromForget) {
7193             if (success) {
7194                 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
7195                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
7196                                                (WifiConfiguration) message.obj);
7197                 return true;
7198             }
7199             replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, WifiManager.ERROR);
7200             return false;
7201         } else {
7202             // Remaining calls are from the removeNetwork path
7203             if (success) {
7204                 replyToMessage(message, message.what, SUCCESS);
7205                 return true;
7206             }
7207             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7208             replyToMessage(message, message.what, FAILURE);
7209             return false;
7210         }
7211     }
7212 
7213     /**
7214      * Private method to handle calling WifiConfigManager to add & enable network configs and reply
7215      * to the message from the sender of the outcome.
7216      *
7217      * @return NetworkUpdateResult with networkId of the added/updated configuration. Will return
7218      * {@link WifiConfiguration#INVALID_NETWORK_ID} in case of error.
7219      */
saveNetworkConfigAndSendReply(Message message)7220     private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
7221         WifiConfiguration config = (WifiConfiguration) message.obj;
7222         if (config == null) {
7223             loge("SAVE_NETWORK with null configuration "
7224                     + mSupplicantStateTracker.getSupplicantStateName()
7225                     + " my state " + getCurrentState().getName());
7226             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7227             replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
7228             return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
7229         }
7230         NetworkUpdateResult result =
7231                 mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
7232         if (!result.isSuccess()) {
7233             loge("SAVE_NETWORK adding/updating config=" + config + " failed");
7234             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7235             replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
7236             return result;
7237         }
7238         if (!mWifiConfigManager.enableNetwork(
7239                 result.getNetworkId(), false, message.sendingUid)) {
7240             loge("SAVE_NETWORK enabling config=" + config + " failed");
7241             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7242             replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
7243             return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
7244         }
7245         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
7246         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
7247         return result;
7248     }
7249 
getLinkPropertiesSummary(LinkProperties lp)7250     private static String getLinkPropertiesSummary(LinkProperties lp) {
7251         List<String> attributes = new ArrayList<>(6);
7252         if (lp.hasIPv4Address()) {
7253             attributes.add("v4");
7254         }
7255         if (lp.hasIPv4DefaultRoute()) {
7256             attributes.add("v4r");
7257         }
7258         if (lp.hasIPv4DnsServer()) {
7259             attributes.add("v4dns");
7260         }
7261         if (lp.hasGlobalIPv6Address()) {
7262             attributes.add("v6");
7263         }
7264         if (lp.hasIPv6DefaultRoute()) {
7265             attributes.add("v6r");
7266         }
7267         if (lp.hasIPv6DnsServer()) {
7268             attributes.add("v6dns");
7269         }
7270 
7271         return TextUtils.join(" ", attributes);
7272     }
7273 
7274     /**
7275      * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
7276      * This should match the network config framework is attempting to connect to.
7277      */
getTargetSsid()7278     private String getTargetSsid() {
7279         WifiConfiguration currentConfig = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
7280         if (currentConfig != null) {
7281             return currentConfig.SSID;
7282         }
7283         return null;
7284     }
7285 
7286     /**
7287      * Send message to WifiP2pServiceImpl.
7288      * @return true if message is sent.
7289      *         false if there is no channel configured for WifiP2pServiceImpl.
7290      */
p2pSendMessage(int what)7291     private boolean p2pSendMessage(int what) {
7292         if (mWifiP2pChannel != null) {
7293             mWifiP2pChannel.sendMessage(what);
7294             return true;
7295         }
7296         return false;
7297     }
7298 
7299     /**
7300      * Send message to WifiP2pServiceImpl with an additional param |arg1|.
7301      * @return true if message is sent.
7302      *         false if there is no channel configured for WifiP2pServiceImpl.
7303      */
p2pSendMessage(int what, int arg1)7304     private boolean p2pSendMessage(int what, int arg1) {
7305         if (mWifiP2pChannel != null) {
7306             mWifiP2pChannel.sendMessage(what, arg1);
7307             return true;
7308         }
7309         return false;
7310     }
7311 
7312     /**
7313      * Check if there is any connection request for WiFi network.
7314      * Note, caller of this helper function must acquire mWifiReqCountLock.
7315      */
hasConnectionRequests()7316     private boolean hasConnectionRequests() {
7317         return mConnectionReqCount > 0 || mUntrustedReqCount > 0;
7318     }
7319 
7320     /**
7321      * Returns whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
7322      */
getIpReachabilityDisconnectEnabled()7323     public boolean getIpReachabilityDisconnectEnabled() {
7324         return mIpReachabilityDisconnectEnabled;
7325     }
7326 
7327     /**
7328      * Sets whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
7329      */
setIpReachabilityDisconnectEnabled(boolean enabled)7330     public void setIpReachabilityDisconnectEnabled(boolean enabled) {
7331         mIpReachabilityDisconnectEnabled = enabled;
7332     }
7333 
7334     /**
7335      * Sends a message to initialize the WifiStateMachine.
7336      *
7337      * @return true if succeeded, false otherwise.
7338      */
syncInitialize(AsyncChannel channel)7339     public boolean syncInitialize(AsyncChannel channel) {
7340         Message resultMsg = channel.sendMessageSynchronously(CMD_INITIALIZE);
7341         boolean result = (resultMsg.arg1 != FAILURE);
7342         resultMsg.recycle();
7343         return result;
7344     }
7345 }
7346