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