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