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