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