WifiStateMachine.java revision 5ccc0a429dfea8ef452f8f63454b013983eb87fe
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 = mFacade.makeWifiScanner(mContext, getHandler().getLooper());
4671
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.numAssociation++;
5178                WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
5179                        config.getNetworkSelectionStatus();
5180                networkSelectionStatus.clearDisableReasonCounter();
5181                networkSelectionStatus.setHasEverConnected(true);
5182            }
5183            // On connect, reset wifiScoreReport
5184            mWifiScoreReport = null;
5185       }
5186    }
5187
5188    void registerDisconnected() {
5189        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5190            // We are switching away from this configuration,
5191            // hence record the time we were connected last
5192            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
5193            if (config != null) {
5194                config.lastDisconnected = System.currentTimeMillis();
5195                if (config.ephemeral) {
5196                    // Remove ephemeral WifiConfigurations from file
5197                    mWifiConfigManager.forgetNetwork(mLastNetworkId);
5198                }
5199            }
5200        }
5201    }
5202
5203    void noteWifiDisabledWhileAssociated() {
5204        // We got disabled by user while we were associated, make note of it
5205        int rssi = mWifiInfo.getRssi();
5206        WifiConfiguration config = getCurrentWifiConfiguration();
5207        if (getCurrentState() == mConnectedState
5208                && rssi != WifiInfo.INVALID_RSSI
5209                && config != null) {
5210            boolean is24GHz = mWifiInfo.is24GHz();
5211            boolean isBadRSSI = (is24GHz && rssi < mWifiConfigManager.mThresholdMinimumRssi24.get())
5212                    || (!is24GHz && rssi < mWifiConfigManager.mThresholdMinimumRssi5.get());
5213            boolean isLowRSSI =
5214                    (is24GHz && rssi < mWifiConfigManager.mThresholdQualifiedRssi24.get())
5215                            || (!is24GHz && mWifiInfo.getRssi() <
5216                                    mWifiConfigManager.mThresholdQualifiedRssi5.get());
5217            boolean isHighRSSI = (is24GHz && rssi
5218                    >= mWifiConfigManager.mThresholdSaturatedRssi24.get())
5219                    || (!is24GHz && mWifiInfo.getRssi()
5220                    >= mWifiConfigManager.mThresholdSaturatedRssi5.get());
5221            if (isBadRSSI) {
5222                // Take note that we got disabled while RSSI was Bad
5223                config.numUserTriggeredWifiDisableLowRSSI++;
5224            } else if (isLowRSSI) {
5225                // Take note that we got disabled while RSSI was Low
5226                config.numUserTriggeredWifiDisableBadRSSI++;
5227            } else if (!isHighRSSI) {
5228                // Take note that we got disabled while RSSI was Not high
5229                config.numUserTriggeredWifiDisableNotHighRSSI++;
5230            }
5231        }
5232    }
5233
5234    WifiConfiguration getCurrentWifiConfiguration() {
5235        if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
5236            return null;
5237        }
5238        return mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
5239    }
5240
5241    ScanResult getCurrentScanResult() {
5242        WifiConfiguration config = getCurrentWifiConfiguration();
5243        if (config == null) {
5244            return null;
5245        }
5246        String BSSID = mWifiInfo.getBSSID();
5247        if (BSSID == null) {
5248            BSSID = mTargetRoamBSSID;
5249        }
5250        ScanDetailCache scanDetailCache =
5251                mWifiConfigManager.getScanDetailCache(config);
5252
5253        if (scanDetailCache == null) {
5254            return null;
5255        }
5256
5257        return scanDetailCache.get(BSSID);
5258    }
5259
5260    String getCurrentBSSID() {
5261        if (linkDebouncing) {
5262            return null;
5263        }
5264        return mLastBssid;
5265    }
5266
5267    class ConnectModeState extends State {
5268
5269        @Override
5270        public void enter() {
5271            // Inform WifiConnectivityManager that Wifi is enabled
5272            if (mWifiConnectivityManager != null) {
5273                mWifiConnectivityManager.setWifiEnabled(true);
5274            }
5275            // Inform metrics that Wifi is Enabled (but not yet connected)
5276            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
5277
5278
5279        }
5280
5281        @Override
5282        public void exit() {
5283            // Inform WifiConnectivityManager that Wifi is disabled
5284            if (mWifiConnectivityManager != null) {
5285                mWifiConnectivityManager.setWifiEnabled(false);
5286            }
5287            // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
5288            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
5289        }
5290
5291        @Override
5292        public boolean processMessage(Message message) {
5293            WifiConfiguration config;
5294            int netId;
5295            boolean ok;
5296            boolean didDisconnect;
5297            String bssid;
5298            String ssid;
5299            NetworkUpdateResult result;
5300            logStateAndMessage(message, this);
5301
5302            switch (message.what) {
5303                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5304                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
5305                    didBlackListBSSID = false;
5306                    bssid = (String) message.obj;
5307                    if (bssid == null || TextUtils.isEmpty(bssid)) {
5308                        // If BSSID is null, use the target roam BSSID
5309                        bssid = mTargetRoamBSSID;
5310                    }
5311                    if (bssid != null) {
5312                        // If we have a BSSID, tell configStore to black list it
5313                        if (mWifiConnectivityManager != null) {
5314                            didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid,
5315                                    false);
5316                        }
5317                    }
5318
5319                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
5320                            WifiConfiguration.NetworkSelectionStatus
5321                            .DISABLED_ASSOCIATION_REJECTION);
5322
5323                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
5324                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
5325                    reportConnectionAttemptEnd(
5326                            WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
5327                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5328                    break;
5329                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5330                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
5331                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
5332                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5333                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
5334                                WifiConfiguration.NetworkSelectionStatus
5335                                        .DISABLED_AUTHENTICATION_FAILURE);
5336                    }
5337                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
5338                    reportConnectionAttemptEnd(
5339                            WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
5340                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5341                    break;
5342                case WifiMonitor.SSID_TEMP_DISABLED:
5343                    Log.e(TAG, "Supplicant SSID temporary disabled:"
5344                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5345                    mWifiConfigManager.updateNetworkSelectionStatus(
5346                            message.arg1,
5347                            WifiConfiguration.NetworkSelectionStatus
5348                            .DISABLED_AUTHENTICATION_FAILURE);
5349                    reportConnectionAttemptEnd(
5350                            WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED,
5351                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5352                    break;
5353                case WifiMonitor.SSID_REENABLED:
5354                    Log.d(TAG, "Supplicant SSID reenable:"
5355                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5356                    // Do not re-enable it in Quality Network Selection since framework has its own
5357                    // Algorithm of disable/enable
5358                    break;
5359                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5360                    SupplicantState state = handleSupplicantStateChange(message);
5361                    // A driver/firmware hang can now put the interface in a down state.
5362                    // We detect the interface going down and recover from it
5363                    if (!SupplicantState.isDriverActive(state)) {
5364                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5365                            handleNetworkDisconnect();
5366                        }
5367                        log("Detected an interface down, restart driver");
5368                        transitionTo(mDriverStoppedState);
5369                        sendMessage(CMD_START_DRIVER);
5370                        break;
5371                    }
5372
5373                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
5374                    // when authentication times out after a successful connection,
5375                    // we can figure this from the supplicant state. If supplicant
5376                    // state is DISCONNECTED, but the mNetworkInfo says we are not
5377                    // disconnected, we need to handle a disconnection
5378                    if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
5379                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5380                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
5381                        handleNetworkDisconnect();
5382                        transitionTo(mDisconnectedState);
5383                    }
5384
5385                    // If we have COMPLETED a connection to a BSSID, start doing
5386                    // DNAv4/DNAv6 -style probing for on-link neighbors of
5387                    // interest (e.g. routers); harmless if none are configured.
5388                    if (state == SupplicantState.COMPLETED) {
5389                        mIpManager.confirmConfiguration();
5390                    }
5391                    break;
5392                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5393                    if (message.arg1 == 1) {
5394                        mWifiNative.disconnect();
5395                        mTemporarilyDisconnectWifi = true;
5396                    } else {
5397                        mWifiNative.reconnect();
5398                        mTemporarilyDisconnectWifi = false;
5399                    }
5400                    break;
5401                case CMD_ADD_OR_UPDATE_NETWORK:
5402                    // Only the current foreground user can modify networks.
5403                    if (!mWifiConfigManager.isCurrentUserProfile(
5404                            UserHandle.getUserId(message.sendingUid))) {
5405                        loge("Only the current foreground user can modify networks "
5406                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5407                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5408                        replyToMessage(message, message.what, FAILURE);
5409                        break;
5410                    }
5411
5412                    config = (WifiConfiguration) message.obj;
5413
5414                    if (!recordUidIfAuthorized(config, message.sendingUid,
5415                            /* onlyAnnotate */ false)) {
5416                        logw("Not authorized to update network "
5417                             + " config=" + config.SSID
5418                             + " cnid=" + config.networkId
5419                             + " uid=" + message.sendingUid);
5420                        replyToMessage(message, message.what, FAILURE);
5421                        break;
5422                    }
5423
5424                    int res = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5425                    if (res < 0) {
5426                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5427                    } else {
5428                        WifiConfiguration curConfig = getCurrentWifiConfiguration();
5429                        if (curConfig != null && config != null) {
5430                            WifiConfiguration.NetworkSelectionStatus networkStatus =
5431                                    config.getNetworkSelectionStatus();
5432                            if (curConfig.priority < config.priority && networkStatus != null
5433                                    && !networkStatus.isNetworkPermanentlyDisabled()) {
5434                                // Interpret this as a connect attempt
5435                                // Set the last selected configuration so as to allow the system to
5436                                // stick the last user choice without persisting the choice
5437                                mWifiConfigManager.setAndEnableLastSelectedConfiguration(res);
5438                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
5439                                boolean persist = mWifiConfigManager
5440                                        .checkConfigOverridePermission(message.sendingUid);
5441                                if (mWifiConnectivityManager != null) {
5442                                    mWifiConnectivityManager.connectToUserSelectNetwork(res,
5443                                            persist);
5444                                }
5445
5446                                // Remember time of last connection attempt
5447                                lastConnectAttemptTimestamp = System.currentTimeMillis();
5448                                mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5449
5450                                // As a courtesy to the caller, trigger a scan now
5451                                startScan(ADD_OR_UPDATE_SOURCE, 0, null, WIFI_WORK_SOURCE);
5452                            }
5453                        }
5454                    }
5455                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
5456                    break;
5457                case CMD_REMOVE_NETWORK:
5458                    // Only the current foreground user can modify networks.
5459                    if (!mWifiConfigManager.isCurrentUserProfile(
5460                            UserHandle.getUserId(message.sendingUid))) {
5461                        loge("Only the current foreground user can modify networks "
5462                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5463                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5464                        replyToMessage(message, message.what, FAILURE);
5465                        break;
5466                    }
5467                    netId = message.arg1;
5468
5469                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
5470                            /* onlyAnnotate */ false)) {
5471                        logw("Not authorized to remove network "
5472                             + " cnid=" + netId
5473                             + " uid=" + message.sendingUid);
5474                        replyToMessage(message, message.what, FAILURE);
5475                        break;
5476                    }
5477
5478                    ok = mWifiConfigManager.removeNetwork(message.arg1);
5479                    if (!ok) {
5480                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5481                    }
5482                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5483                    break;
5484                case CMD_ENABLE_NETWORK:
5485                    // Only the current foreground user can modify networks.
5486                    if (!mWifiConfigManager.isCurrentUserProfile(
5487                            UserHandle.getUserId(message.sendingUid))) {
5488                        loge("Only the current foreground user can modify networks "
5489                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5490                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5491                        replyToMessage(message, message.what, FAILURE);
5492                        break;
5493                    }
5494
5495                    boolean disableOthers = message.arg2 == 1;
5496                    netId = message.arg1;
5497                    config = mWifiConfigManager.getWifiConfiguration(netId);
5498                    if (config == null) {
5499                        loge("No network with id = " + netId);
5500                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5501                        replyToMessage(message, message.what, FAILURE);
5502                        break;
5503                    }
5504
5505                    // disable other only means select this network, does not mean all other
5506                    // networks need to be disabled
5507                    if (disableOthers) {
5508                        // Remember time of last connection attempt
5509                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5510                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5511                    }
5512                    // Cancel auto roam requests
5513                    autoRoamSetBSSID(netId, "any");
5514
5515                    int uid = message.sendingUid;
5516                    mWifiConfigManager.updateNetworkSelectionStatus(config,
5517                                WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
5518                    mWifiConfigManager.setLatestUserSelectedConfiguration(config);
5519                    ok = mWifiConfigManager.enableNetwork(netId, disableOthers, uid);
5520                    if (!ok) {
5521                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5522                    } else if (disableOthers) {
5523                        mTargetNetworkId = netId;
5524                    }
5525
5526                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5527                    break;
5528                case CMD_ENABLE_ALL_NETWORKS:
5529                    long time = android.os.SystemClock.elapsedRealtime();
5530                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
5531                        mWifiConfigManager.enableAllNetworks();
5532                        mLastEnableAllNetworksTime = time;
5533                    }
5534                    break;
5535                case WifiManager.DISABLE_NETWORK:
5536                    if (mWifiConfigManager.updateNetworkSelectionStatus(message.arg1,
5537                            WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) {
5538                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
5539                    } else {
5540                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5541                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5542                                WifiManager.ERROR);
5543                    }
5544                    break;
5545                case CMD_DISABLE_EPHEMERAL_NETWORK:
5546                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
5547                    if (config != null) {
5548                        if (config.networkId == mLastNetworkId) {
5549                            // Disconnect and let autojoin reselect a new network
5550                            sendMessage(CMD_DISCONNECT);
5551                        }
5552                    }
5553                    break;
5554                case CMD_BLACKLIST_NETWORK:
5555                    mWifiConfigManager.blackListBssid((String) message.obj);
5556                    break;
5557                case CMD_CLEAR_BLACKLIST:
5558                    mWifiConfigManager.clearBssidBlacklist();
5559                    break;
5560                case CMD_SAVE_CONFIG:
5561                    ok = mWifiConfigManager.saveConfig();
5562
5563                    if (DBG) logd("did save config " + ok);
5564                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
5565
5566                    // Inform the backup manager about a data change
5567                    mBackupManagerProxy.notifyDataChanged();
5568                    break;
5569                case CMD_GET_CONFIGURED_NETWORKS:
5570                    replyToMessage(message, message.what,
5571                            mWifiConfigManager.getSavedNetworks());
5572                    break;
5573                case WifiMonitor.SUP_REQUEST_IDENTITY:
5574                    int networkId = message.arg2;
5575                    boolean identitySent = false;
5576                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
5577
5578                    if (targetWificonfiguration != null
5579                            && targetWificonfiguration.enterpriseConfig != null) {
5580                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
5581                    }
5582
5583                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
5584                    if (targetWificonfiguration != null
5585                            && targetWificonfiguration.networkId == networkId
5586                            && targetWificonfiguration.allowedKeyManagement
5587                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X)
5588                            &&  (eapMethod == WifiEnterpriseConfig.Eap.SIM
5589                            || eapMethod == WifiEnterpriseConfig.Eap.AKA
5590                            || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
5591                        TelephonyManager tm = (TelephonyManager)
5592                                mContext.getSystemService(Context.TELEPHONY_SERVICE);
5593                        if (tm != null) {
5594                            String imsi = tm.getSubscriberId();
5595                            String mccMnc = "";
5596
5597                            if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
5598                                 mccMnc = tm.getSimOperator();
5599
5600                            String identity = buildIdentity(eapMethod, imsi, mccMnc);
5601
5602                            if (!identity.isEmpty()) {
5603                                mWifiNative.simIdentityResponse(networkId, identity);
5604                                identitySent = true;
5605                            }
5606                        }
5607                    }
5608                    if (!identitySent) {
5609                        // Supplicant lacks credentials to connect to that network, hence black list
5610                        ssid = (String) message.obj;
5611                        if (targetWificonfiguration != null && ssid != null
5612                                && targetWificonfiguration.SSID != null
5613                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
5614                            mWifiConfigManager.updateNetworkSelectionStatus(targetWificonfiguration,
5615                                    WifiConfiguration.NetworkSelectionStatus
5616                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
5617                        }
5618                        // Disconnect now, as we don't have any way to fullfill
5619                        // the  supplicant request.
5620                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
5621                                WifiConfiguration.INVALID_NETWORK_ID);
5622                        mWifiNative.disconnect();
5623                    }
5624                    break;
5625                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5626                    logd("Received SUP_REQUEST_SIM_AUTH");
5627                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5628                    if (requestData != null) {
5629                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5630                            handleGsmAuthRequest(requestData);
5631                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5632                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5633                            handle3GAuthRequest(requestData);
5634                        }
5635                    } else {
5636                        loge("Invalid sim auth request");
5637                    }
5638                    break;
5639                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5640                    replyToMessage(message, message.what,
5641                            mWifiConfigManager.getPrivilegedSavedNetworks());
5642                    break;
5643                case CMD_GET_MATCHING_CONFIG:
5644                    replyToMessage(message, message.what,
5645                            mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
5646                    break;
5647                /* Do a redundant disconnect without transition */
5648                case CMD_DISCONNECT:
5649                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
5650                            (WifiConfiguration.INVALID_NETWORK_ID);
5651                    mWifiNative.disconnect();
5652                    break;
5653                case CMD_RECONNECT:
5654                    if (mWifiConnectivityManager != null) {
5655                        mWifiConnectivityManager.forceConnectivityScan();
5656                    }
5657                    break;
5658                case CMD_REASSOCIATE:
5659                    lastConnectAttemptTimestamp = System.currentTimeMillis();
5660                    mWifiNative.reassociate();
5661                    break;
5662                case CMD_RELOAD_TLS_AND_RECONNECT:
5663                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
5664                        logd("Reconnecting to give a chance to un-connected TLS networks");
5665                        mWifiNative.disconnect();
5666                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5667                        mWifiNative.reconnect();
5668                    }
5669                    break;
5670                case CMD_AUTO_ROAM:
5671                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5672                    return HANDLED;
5673                case CMD_AUTO_CONNECT:
5674                    /* Work Around: wpa_supplicant can get in a bad state where it returns a non
5675                     * associated status to the STATUS command but somehow-someplace still thinks
5676                     * it is associated and thus will ignore select/reconnect command with
5677                     * following message:
5678                     * "Already associated with the selected network - do nothing"
5679                     *
5680                     * Hence, sends a disconnect to supplicant first.
5681                     */
5682                    didDisconnect = false;
5683                    if (getCurrentState() != mDisconnectedState) {
5684                        /** Supplicant will ignore the reconnect if we are currently associated,
5685                         * hence trigger a disconnect
5686                         */
5687                        didDisconnect = true;
5688                        mWifiNative.disconnect();
5689                    }
5690
5691                    /* connect command coming from auto-join */
5692                    netId = message.arg1;
5693                    mTargetNetworkId = netId;
5694                    mTargetRoamBSSID = (String) message.obj;
5695                    config = mWifiConfigManager.getWifiConfiguration(netId);
5696                    logd("CMD_AUTO_CONNECT sup state "
5697                            + mSupplicantStateTracker.getSupplicantStateName()
5698                            + " my state " + getCurrentState().getName()
5699                            + " nid=" + Integer.toString(netId)
5700                            + " roam=" + Boolean.toString(mAutoRoaming));
5701                    if (config == null) {
5702                        loge("AUTO_CONNECT and no config, bail out...");
5703                        break;
5704                    }
5705
5706                    /* Make sure we cancel any previous roam request */
5707                    setTargetBssid(config, mTargetRoamBSSID);
5708
5709                    /* Save the network config */
5710                    logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
5711                            + " nid=" + Integer.toString(netId));
5712                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
5713                    netId = result.getNetworkId();
5714                    logd("CMD_AUTO_CONNECT did save config -> "
5715                            + " nid=" + Integer.toString(netId));
5716
5717                    // Since we updated the config,read it back from config store:
5718                    config = mWifiConfigManager.getWifiConfiguration(netId);
5719                    if (config == null) {
5720                        loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
5721                        break;
5722                    }
5723                    if (netId != config.networkId) {
5724                        loge("CMD_AUTO_CONNECT couldn't update the config, want"
5725                                + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
5726                        break;
5727                    }
5728
5729                    if (deferForUserInput(message, netId, false)) {
5730                        break;
5731                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5732                                                                   WifiConfiguration.USER_BANNED) {
5733                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5734                                WifiManager.NOT_AUTHORIZED);
5735                        break;
5736                    }
5737
5738                    // If we're autojoining a network that the user or an app explicitly selected,
5739                    // keep track of the UID that selected it.
5740                    // TODO(b/26786318): Keep track of the lastSelectedConfiguration and the
5741                    // lastConnectUid on a per-user basis.
5742                    int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
5743
5744                    //Start a new ConnectionEvent due to auto_connect, assume we are connecting
5745                    //between different networks due to QNS, setting ROAM_UNRELATED
5746                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5747                            WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
5748                    if (!didDisconnect) {
5749                        //If we were originally disconnected, then this was not any kind of ROAM
5750                        mWifiMetrics.setConnectionEventRoamType(
5751                                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
5752                    }
5753                    //Determine if this CONNECTION is for a user selection
5754                    if (mWifiConfigManager.isLastSelectedConfiguration(config)
5755                            && mWifiConfigManager.isCurrentUserProfile(
5756                                    UserHandle.getUserId(config.lastConnectUid))) {
5757                        lastConnectUid = config.lastConnectUid;
5758                        mWifiMetrics.setConnectionEventRoamType(
5759                                WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
5760                    }
5761                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
5762                            lastConnectUid) && mWifiNative.reconnect()) {
5763                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5764                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
5765                        config = mWifiConfigManager.getWifiConfiguration(netId);
5766                        if (config != null
5767                                && !mWifiConfigManager.isLastSelectedConfiguration(config)) {
5768                            // If we autojoined a different config than the user selected one,
5769                            // it means we could not see the last user selection,
5770                            // or that the last user selection was faulty and ended up blacklisted
5771                            // for some reason (in which case the user is notified with an error
5772                            // message in the Wifi picker), and thus we managed to auto-join away
5773                            // from the selected  config. -> in that case we need to forget
5774                            // the selection because we don't want to abruptly switch back to it.
5775                            //
5776                            // Note that the user selection is also forgotten after a period of time
5777                            // during which the device has been disconnected.
5778                            // The default value is 30 minutes : see the code path at bottom of
5779                            // setScanResults() function.
5780                            mWifiConfigManager.
5781                                 setAndEnableLastSelectedConfiguration(
5782                                         WifiConfiguration.INVALID_NETWORK_ID);
5783                        }
5784                        mAutoRoaming = false;
5785                        if (isRoaming() || linkDebouncing) {
5786                            transitionTo(mRoamingState);
5787                        } else if (didDisconnect) {
5788                            transitionTo(mDisconnectingState);
5789                        }
5790                    } else {
5791                        loge("Failed to connect config: " + config + " netId: " + netId);
5792                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5793                                WifiManager.ERROR);
5794                        reportConnectionAttemptEnd(
5795                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5796                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5797                        break;
5798                    }
5799                    break;
5800                case CMD_REMOVE_APP_CONFIGURATIONS:
5801                    mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
5802                    break;
5803                case CMD_REMOVE_USER_CONFIGURATIONS:
5804                    mWifiConfigManager.removeNetworksForUser(message.arg1);
5805                    break;
5806                case WifiManager.CONNECT_NETWORK:
5807                    // Only the current foreground user can modify networks.
5808                    if (!mWifiConfigManager.isCurrentUserProfile(
5809                            UserHandle.getUserId(message.sendingUid))) {
5810                        loge("Only the current foreground user can modify networks "
5811                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5812                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5813                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5814                                       WifiManager.NOT_AUTHORIZED);
5815                        break;
5816                    }
5817
5818                    /**
5819                     *  The connect message can contain a network id passed as arg1 on message or
5820                     * or a config passed as obj on message.
5821                     * For a new network, a config is passed to create and connect.
5822                     * For an existing network, a network id is passed
5823                     */
5824                    netId = message.arg1;
5825                    config = (WifiConfiguration) message.obj;
5826                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5827                    boolean updatedExisting = false;
5828
5829                    /* Save the network config */
5830                    if (config != null) {
5831                        // When connecting to an access point, WifiStateMachine wants to update the
5832                        // relevant config with administrative data. This update should not be
5833                        // considered a 'real' update, therefore lockdown by Device Owner must be
5834                        // disregarded.
5835                        if (!recordUidIfAuthorized(config, message.sendingUid,
5836                                /* onlyAnnotate */ true)) {
5837                            logw("Not authorized to update network "
5838                                 + " config=" + config.SSID
5839                                 + " cnid=" + config.networkId
5840                                 + " uid=" + message.sendingUid);
5841                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5842                                           WifiManager.NOT_AUTHORIZED);
5843                            break;
5844                        }
5845                        String configKey = config.configKey(true /* allowCached */);
5846                        WifiConfiguration savedConfig =
5847                                mWifiConfigManager.getWifiConfiguration(configKey);
5848                        if (savedConfig != null) {
5849                            // There is an existing config with this netId, but it wasn't exposed
5850                            // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigManager#
5851                            // getConfiguredNetworks). Remove those bits and update the config.
5852                            config = savedConfig;
5853                            logd("CONNECT_NETWORK updating existing config with id=" +
5854                                    config.networkId + " configKey=" + configKey);
5855                            config.ephemeral = false;
5856                            mWifiConfigManager.updateNetworkSelectionStatus(config,
5857                                    WifiConfiguration.NetworkSelectionStatus
5858                                    .NETWORK_SELECTION_ENABLE);
5859                            updatedExisting = true;
5860                        }
5861
5862                        result = mWifiConfigManager.saveNetwork(config, message.sendingUid);
5863                        netId = result.getNetworkId();
5864                    }
5865                    config = mWifiConfigManager.getWifiConfiguration(netId);
5866                    if (config == null) {
5867                        logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
5868                                + mSupplicantStateTracker.getSupplicantStateName() + " my state "
5869                                + getCurrentState().getName());
5870                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5871                                WifiManager.ERROR);
5872                        break;
5873                    }
5874                    mTargetNetworkId = netId;
5875                    autoRoamSetBSSID(netId, "any");
5876                    if (message.sendingUid == Process.WIFI_UID
5877                        || message.sendingUid == Process.SYSTEM_UID) {
5878                        // As a sanity measure, clear the BSSID in the supplicant network block.
5879                        // If system or Wifi Settings want to connect, they will not
5880                        // specify the BSSID.
5881                        // If an app however had added a BSSID to this configuration, and the BSSID
5882                        // was wrong, Then we would forever fail to connect until that BSSID
5883                        // is cleaned up.
5884                        clearConfigBSSID(config, "CONNECT_NETWORK");
5885                    }
5886
5887                    if (deferForUserInput(message, netId, true)) {
5888                        break;
5889                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5890                                                                    WifiConfiguration.USER_BANNED) {
5891                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5892                                WifiManager.NOT_AUTHORIZED);
5893                        break;
5894                    }
5895
5896                    mAutoRoaming = false;
5897
5898                    /* Tell network selection the user did try to connect to that network if from
5899                    settings */
5900                    boolean persist =
5901                        mWifiConfigManager.checkConfigOverridePermission(message.sendingUid);
5902
5903
5904                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(netId);
5905                    if (mWifiConnectivityManager != null) {
5906                        mWifiConnectivityManager.connectToUserSelectNetwork(netId, persist);
5907                    }
5908                    didDisconnect = false;
5909                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
5910                            && mLastNetworkId != netId) {
5911                        /** Supplicant will ignore the reconnect if we are currently associated,
5912                         * hence trigger a disconnect
5913                         */
5914                        didDisconnect = true;
5915                        mWifiNative.disconnect();
5916                    }
5917
5918                    //Start a new ConnectionEvent due to connect_network, this is always user
5919                    //selected
5920                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5921                            WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
5922                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ true,
5923                            message.sendingUid) && mWifiNative.reconnect()) {
5924                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5925                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
5926
5927                        /* The state tracker handles enabling networks upon completion/failure */
5928                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
5929                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
5930                        if (didDisconnect) {
5931                            /* Expect a disconnection from the old connection */
5932                            transitionTo(mDisconnectingState);
5933                        } else if (updatedExisting && getCurrentState() == mConnectedState &&
5934                                getCurrentWifiConfiguration().networkId == netId) {
5935                            // Update the current set of network capabilities, but stay in the
5936                            // current state.
5937                            updateCapabilities(config);
5938                        } else {
5939                            /**
5940                             * Directly go to disconnected state where we
5941                             * process the connection events from supplicant
5942                             */
5943                            transitionTo(mDisconnectedState);
5944                        }
5945                    } else {
5946                        loge("Failed to connect config: " + config + " netId: " + netId);
5947                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5948                                WifiManager.ERROR);
5949                        reportConnectionAttemptEnd(
5950                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5951                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5952                        break;
5953                    }
5954                    break;
5955                case WifiManager.SAVE_NETWORK:
5956                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5957                    // Fall thru
5958                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
5959                    // Only the current foreground user can modify networks.
5960                    if (!mWifiConfigManager.isCurrentUserProfile(
5961                            UserHandle.getUserId(message.sendingUid))) {
5962                        loge("Only the current foreground user can modify networks "
5963                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5964                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5965                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5966                                WifiManager.NOT_AUTHORIZED);
5967                        break;
5968                    }
5969
5970                    lastSavedConfigurationAttempt = null; // Used for debug
5971                    config = (WifiConfiguration) message.obj;
5972                    if (config == null) {
5973                        loge("ERROR: SAVE_NETWORK with null configuration"
5974                                + mSupplicantStateTracker.getSupplicantStateName()
5975                                + " my state " + getCurrentState().getName());
5976                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5977                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5978                                WifiManager.ERROR);
5979                        break;
5980                    }
5981                    lastSavedConfigurationAttempt = new WifiConfiguration(config);
5982                    int nid = config.networkId;
5983                    logd("SAVE_NETWORK id=" + Integer.toString(nid)
5984                                + " config=" + config.SSID
5985                                + " nid=" + config.networkId
5986                                + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
5987                                + " my state " + getCurrentState().getName());
5988
5989                    // Only record the uid if this is user initiated
5990                    boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
5991                    if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
5992                            /* onlyAnnotate */ false)) {
5993                        logw("Not authorized to update network "
5994                             + " config=" + config.SSID
5995                             + " cnid=" + config.networkId
5996                             + " uid=" + message.sendingUid);
5997                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5998                                       WifiManager.NOT_AUTHORIZED);
5999                        break;
6000                    }
6001
6002                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
6003                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
6004                        if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
6005                            if (result.hasIpChanged()) {
6006                                // The currently connection configuration was changed
6007                                // We switched from DHCP to static or from static to DHCP, or the
6008                                // static IP address has changed.
6009                                log("Reconfiguring IP on connection");
6010                                // TODO: clear addresses and disable IPv6
6011                                // to simplify obtainingIpState.
6012                                transitionTo(mObtainingIpState);
6013                            }
6014                            if (result.hasProxyChanged()) {
6015                                log("Reconfiguring proxy on connection");
6016                                mIpManager.setHttpProxy(
6017                                        mWifiConfigManager.getProxyProperties(mLastNetworkId));
6018                            }
6019                        }
6020                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
6021                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6022
6023                        if (DBG) {
6024                           logd("Success save network nid="
6025                                    + Integer.toString(result.getNetworkId()));
6026                        }
6027
6028                        /**
6029                         * If the command comes from WifiManager, then
6030                         * tell autojoin the user did try to modify and save that network,
6031                         * and interpret the SAVE_NETWORK as a request to connect
6032                         */
6033                        boolean user = message.what == WifiManager.SAVE_NETWORK;
6034
6035                        // Did this connect come from settings
6036                        boolean persistConnect =
6037                                mWifiConfigManager.checkConfigOverridePermission(
6038                                        message.sendingUid);
6039
6040                        if (user) {
6041                            mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
6042                            mWifiConfigManager.writeKnownNetworkHistory();
6043                        }
6044
6045                        if (mWifiConnectivityManager != null) {
6046                            mWifiConnectivityManager.connectToUserSelectNetwork(
6047                                    result.getNetworkId(), persistConnect);
6048                        }
6049                    } else {
6050                        loge("Failed to save network");
6051                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6052                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6053                                WifiManager.ERROR);
6054                    }
6055                    break;
6056                case WifiManager.FORGET_NETWORK:
6057                    // Only the current foreground user can modify networks.
6058                    if (!mWifiConfigManager.isCurrentUserProfile(
6059                            UserHandle.getUserId(message.sendingUid))) {
6060                        loge("Only the current foreground user can modify networks "
6061                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
6062                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6063                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6064                                WifiManager.NOT_AUTHORIZED);
6065                        break;
6066                    }
6067
6068                    // Debug only, remember last configuration that was forgotten
6069                    WifiConfiguration toRemove
6070                            = mWifiConfigManager.getWifiConfiguration(message.arg1);
6071                    if (toRemove == null) {
6072                        lastForgetConfigurationAttempt = null;
6073                    } else {
6074                        lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
6075                    }
6076                    // check that the caller owns this network
6077                    netId = message.arg1;
6078
6079                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
6080                            /* onlyAnnotate */ false)) {
6081                        logw("Not authorized to forget network "
6082                             + " cnid=" + netId
6083                             + " uid=" + message.sendingUid);
6084                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6085                                WifiManager.NOT_AUTHORIZED);
6086                        break;
6087                    }
6088
6089                    if (mWifiConfigManager.forgetNetwork(message.arg1)) {
6090                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
6091                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
6092                                (WifiConfiguration) message.obj);
6093                    } else {
6094                        loge("Failed to forget network");
6095                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6096                                WifiManager.ERROR);
6097                    }
6098                    break;
6099                case WifiManager.START_WPS:
6100                    WpsInfo wpsInfo = (WpsInfo) message.obj;
6101                    WpsResult wpsResult;
6102                    switch (wpsInfo.setup) {
6103                        case WpsInfo.PBC:
6104                            wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
6105                            break;
6106                        case WpsInfo.KEYPAD:
6107                            wpsResult = mWifiConfigManager.startWpsWithPinFromAccessPoint(wpsInfo);
6108                            break;
6109                        case WpsInfo.DISPLAY:
6110                            wpsResult = mWifiConfigManager.startWpsWithPinFromDevice(wpsInfo);
6111                            break;
6112                        default:
6113                            wpsResult = new WpsResult(Status.FAILURE);
6114                            loge("Invalid setup for WPS");
6115                            break;
6116                    }
6117                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
6118                            (WifiConfiguration.INVALID_NETWORK_ID);
6119                    if (wpsResult.status == Status.SUCCESS) {
6120                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
6121                        transitionTo(mWpsRunningState);
6122                    } else {
6123                        loge("Failed to start WPS with config " + wpsInfo.toString());
6124                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
6125                    }
6126                    break;
6127                case CMD_ASSOCIATED_BSSID:
6128                    // This is where we can confirm the connection BSSID. Use it to find the
6129                    // right ScanDetail to populate metrics.
6130                    String someBssid = (String) message.obj;
6131                    if (someBssid != null) {
6132                        //Get the config associated with this connection attempt
6133                        WifiConfiguration someConf =
6134                                mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
6135                        // Get the ScanDetail associated with this BSSID
6136                        ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCache(
6137                                someConf);
6138                        if (scanDetailCache != null) {
6139                            mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
6140                                    someBssid));
6141                        }
6142                    }
6143                    return NOT_HANDLED;
6144                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6145                    if (DBG) log("Network connection established");
6146                    mLastNetworkId = message.arg1;
6147                    mLastBssid = (String) message.obj;
6148
6149                    mWifiInfo.setBSSID(mLastBssid);
6150                    mWifiInfo.setNetworkId(mLastNetworkId);
6151                    mWifiQualifiedNetworkSelector
6152                            .enableBssidForQualityNetworkSelection(mLastBssid, true);
6153                    sendNetworkStateChangeBroadcast(mLastBssid);
6154                    transitionTo(mObtainingIpState);
6155                    break;
6156                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6157                    // Calling handleNetworkDisconnect here is redundant because we might already
6158                    // have called it when leaving L2ConnectedState to go to disconnecting state
6159                    // or thru other path
6160                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
6161                    // if they are valid, and only in this case call handleNEtworkDisconnect,
6162                    // TODO: this should be fixed for a L MR release
6163                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
6164                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
6165                    // at the chip etc...
6166                    if (DBG) log("ConnectModeState: Network connection lost ");
6167                    handleNetworkDisconnect();
6168                    transitionTo(mDisconnectedState);
6169                    break;
6170                case CMD_ADD_PASSPOINT_MO:
6171                    res = mWifiConfigManager.addPasspointManagementObject((String) message.obj);
6172                    replyToMessage(message, message.what, res);
6173                    break;
6174                case CMD_MODIFY_PASSPOINT_MO:
6175                    if (message.obj != null) {
6176                        Bundle bundle = (Bundle) message.obj;
6177                        ArrayList<PasspointManagementObjectDefinition> mos =
6178                                bundle.getParcelableArrayList("MOS");
6179                        res = mWifiConfigManager.modifyPasspointMo(bundle.getString("FQDN"), mos);
6180                    } else {
6181                        res = 0;
6182                    }
6183                    replyToMessage(message, message.what, res);
6184
6185                    break;
6186                case CMD_QUERY_OSU_ICON:
6187                    if (mWifiConfigManager.queryPasspointIcon(
6188                            ((Bundle) message.obj).getLong("BSSID"),
6189                            ((Bundle) message.obj).getString("FILENAME"))) {
6190                        res = 1;
6191                    } else {
6192                        res = 0;
6193                    }
6194                    replyToMessage(message, message.what, res);
6195                    break;
6196                case CMD_MATCH_PROVIDER_NETWORK:
6197                    res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
6198                    replyToMessage(message, message.what, res);
6199                    break;
6200                default:
6201                    return NOT_HANDLED;
6202            }
6203            return HANDLED;
6204        }
6205    }
6206
6207    private void updateCapabilities(WifiConfiguration config) {
6208        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
6209        if (config != null) {
6210            if (config.ephemeral) {
6211                networkCapabilities.removeCapability(
6212                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
6213            } else {
6214                networkCapabilities.addCapability(
6215                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
6216            }
6217
6218            networkCapabilities.setSignalStrength(
6219                    (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI)
6220                    ? mWifiInfo.getRssi()
6221                    : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
6222        }
6223
6224        if (mWifiInfo.getMeteredHint()) {
6225            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
6226        }
6227
6228        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
6229    }
6230
6231    private class WifiNetworkAgent extends NetworkAgent {
6232        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
6233                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
6234            super(l, c, TAG, ni, nc, lp, score, misc);
6235        }
6236        protected void unwanted() {
6237            // Ignore if we're not the current networkAgent.
6238            if (this != mNetworkAgent) return;
6239            if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
6240                    + Integer.toString(mWifiInfo.score));
6241            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
6242        }
6243
6244        @Override
6245        protected void networkStatus(int status, String redirectUrl) {
6246            if (this != mNetworkAgent) return;
6247            if (status == NetworkAgent.INVALID_NETWORK) {
6248                if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
6249                        + Integer.toString(mWifiInfo.score));
6250                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
6251            } else if (status == NetworkAgent.VALID_NETWORK) {
6252                if (DBG) {
6253                    log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
6254                            + Integer.toString(mWifiInfo.score));
6255                }
6256                doNetworkStatus(status);
6257            }
6258        }
6259
6260        @Override
6261        protected void saveAcceptUnvalidated(boolean accept) {
6262            if (this != mNetworkAgent) return;
6263            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
6264        }
6265
6266        @Override
6267        protected void startPacketKeepalive(Message msg) {
6268            WifiStateMachine.this.sendMessage(
6269                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
6270        }
6271
6272        @Override
6273        protected void stopPacketKeepalive(Message msg) {
6274            WifiStateMachine.this.sendMessage(
6275                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
6276        }
6277
6278        @Override
6279        protected void setSignalStrengthThresholds(int[] thresholds) {
6280            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
6281            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
6282            //    MAX_VALUE at the start/end of the thresholds array if necessary.
6283            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
6284            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
6285            //    re-arm the hardware event. This needs to be done on the state machine thread to
6286            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
6287            //    sent in the NetworkCapabilities) must be the one received from the hardware event
6288            //    received, or we might skip callbacks.
6289            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
6290            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
6291            if (thresholds.length == 0) {
6292                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
6293                        mWifiInfo.getRssi());
6294                return;
6295            }
6296            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
6297            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
6298            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
6299            Arrays.sort(rssiVals);
6300            byte[] rssiRange = new byte[rssiVals.length];
6301            for (int i = 0; i < rssiVals.length; i++) {
6302                int val = rssiVals[i];
6303                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
6304                    rssiRange[i] = (byte) val;
6305                } else {
6306                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
6307                            + Arrays.toString(rssiVals));
6308                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
6309                            mWifiInfo.getRssi());
6310                    return;
6311                }
6312            }
6313            // TODO: Do we quash rssi values in this sorted array which are very close?
6314            mRssiRanges = rssiRange;
6315            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
6316                    mWifiInfo.getRssi());
6317        }
6318
6319        @Override
6320        protected void preventAutomaticReconnect() {
6321            if (this != mNetworkAgent) return;
6322            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
6323        }
6324    }
6325
6326    void unwantedNetwork(int reason) {
6327        sendMessage(CMD_UNWANTED_NETWORK, reason);
6328    }
6329
6330    void doNetworkStatus(int status) {
6331        sendMessage(CMD_NETWORK_STATUS, status);
6332    }
6333
6334    // rfc4186 & rfc4187:
6335    // create Permanent Identity base on IMSI,
6336    // identity = usernam@realm
6337    // with username = prefix | IMSI
6338    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
6339    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
6340        String mcc;
6341        String mnc;
6342        String prefix;
6343
6344        if (imsi == null || imsi.isEmpty())
6345            return "";
6346
6347        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
6348            prefix = "1";
6349        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
6350            prefix = "0";
6351        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
6352            prefix = "6";
6353        else  // not a valide EapMethod
6354            return "";
6355
6356        /* extract mcc & mnc from mccMnc */
6357        if (mccMnc != null && !mccMnc.isEmpty()) {
6358            mcc = mccMnc.substring(0, 3);
6359            mnc = mccMnc.substring(3);
6360            if (mnc.length() == 2)
6361                mnc = "0" + mnc;
6362        } else {
6363            // extract mcc & mnc from IMSI, assume mnc size is 3
6364            mcc = imsi.substring(0, 3);
6365            mnc = imsi.substring(3, 6);
6366        }
6367
6368        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
6369    }
6370
6371    boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
6372        if (config == null)
6373            return false;
6374
6375        // We are still seeing a fairly high power consumption triggered by autojoin scans
6376        // Hence do partial scans only for PSK configuration that are roamable since the
6377        // primary purpose of the partial scans is roaming.
6378        // Full badn scans with exponential backoff for the purpose or extended roaming and
6379        // network switching are performed unconditionally.
6380        ScanDetailCache scanDetailCache =
6381                mWifiConfigManager.getScanDetailCache(config);
6382        if (scanDetailCache == null
6383                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
6384                || scanDetailCache.size() > 6) {
6385            //return true but to not trigger the scan
6386            return true;
6387        }
6388        HashSet<Integer> freqs = mWifiConfigManager.makeChannelList(config,
6389                ONE_HOUR_MILLI, restrictChannelList);
6390        if (freqs != null && freqs.size() != 0) {
6391            //if (DBG) {
6392            logd("starting scan for " + config.configKey() + " with " + freqs);
6393            //}
6394            Set<Integer> hiddenNetworkIds = new HashSet<>();
6395            if (config.hiddenSSID) {
6396                hiddenNetworkIds.add(config.networkId);
6397            }
6398            // Call wifi native to start the scan
6399            if (startScanNative(freqs, hiddenNetworkIds, WIFI_WORK_SOURCE)) {
6400                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
6401            } else {
6402                // used for debug only, mark scan as failed
6403                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
6404            }
6405            return true;
6406        } else {
6407            if (DBG) logd("no channels for " + config.configKey());
6408            return false;
6409        }
6410    }
6411
6412    void clearCurrentConfigBSSID(String dbg) {
6413        // Clear the bssid in the current config's network block
6414        WifiConfiguration config = getCurrentWifiConfiguration();
6415        if (config == null)
6416            return;
6417        clearConfigBSSID(config, dbg);
6418    }
6419    void clearConfigBSSID(WifiConfiguration config, String dbg) {
6420        if (config == null)
6421            return;
6422        if (DBG) {
6423            logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
6424                    + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
6425                    + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
6426        }
6427        if (DBG) {
6428           logd(dbg + " " + config.SSID
6429                    + " nid=" + Integer.toString(config.networkId));
6430        }
6431        mWifiConfigManager.saveWifiConfigBSSID(config, "any");
6432    }
6433
6434    class L2ConnectedState extends State {
6435        @Override
6436        public void enter() {
6437            mRssiPollToken++;
6438            if (mEnableRssiPolling) {
6439                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
6440            }
6441            if (mNetworkAgent != null) {
6442                loge("Have NetworkAgent when entering L2Connected");
6443                setNetworkDetailedState(DetailedState.DISCONNECTED);
6444            }
6445            setNetworkDetailedState(DetailedState.CONNECTING);
6446
6447            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
6448                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
6449                    mLinkProperties, 60, mNetworkMisc);
6450
6451            // We must clear the config BSSID, as the wifi chipset may decide to roam
6452            // from this point on and having the BSSID specified in the network block would
6453            // cause the roam to faile and the device to disconnect
6454            clearCurrentConfigBSSID("L2ConnectedState");
6455            mCountryCode.setReadyForChange(false);
6456            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
6457        }
6458
6459        @Override
6460        public void exit() {
6461            mIpManager.stop();
6462
6463            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
6464            // Bug: 15347363
6465            // For paranoia's sake, call handleNetworkDisconnect
6466            // only if BSSID is null or last networkId
6467            // is not invalid.
6468            if (DBG) {
6469                StringBuilder sb = new StringBuilder();
6470                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
6471                if (mLastBssid !=null) {
6472                    sb.append(" ").append(mLastBssid);
6473                }
6474            }
6475            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6476                handleNetworkDisconnect();
6477            }
6478            mCountryCode.setReadyForChange(true);
6479            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
6480        }
6481
6482        @Override
6483        public boolean processMessage(Message message) {
6484            logStateAndMessage(message, this);
6485
6486            switch (message.what) {
6487                case DhcpClient.CMD_PRE_DHCP_ACTION:
6488                    handlePreDhcpSetup();
6489                    break;
6490                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
6491                    mIpManager.completedPreDhcpAction();
6492                    break;
6493                case DhcpClient.CMD_POST_DHCP_ACTION:
6494                    handlePostDhcpSetup();
6495                    // We advance to mConnectedState because IpManager will also send a
6496                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
6497                    // which calls updateLinkProperties, which then sends
6498                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
6499                    //
6500                    // In the event of failure, we transition to mDisconnectingState
6501                    // similarly--via messages sent back from IpManager.
6502                    break;
6503                case CMD_IPV4_PROVISIONING_SUCCESS: {
6504                    handleIPv4Success((DhcpResults) message.obj);
6505                    sendNetworkStateChangeBroadcast(mLastBssid);
6506                    break;
6507                }
6508                case CMD_IPV4_PROVISIONING_FAILURE: {
6509                    handleIPv4Failure();
6510                    break;
6511                }
6512                case CMD_IP_CONFIGURATION_SUCCESSFUL:
6513                    handleSuccessfulIpConfiguration();
6514                    reportConnectionAttemptEnd(
6515                            WifiMetrics.ConnectionEvent.FAILURE_NONE,
6516                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6517                    sendConnectedState();
6518                    transitionTo(mConnectedState);
6519                    break;
6520                case CMD_IP_CONFIGURATION_LOST:
6521                    // Get Link layer stats so that we get fresh tx packet counters.
6522                    getWifiLinkLayerStats(true);
6523                    handleIpConfigurationLost();
6524                    transitionTo(mDisconnectingState);
6525                    break;
6526                case CMD_IP_REACHABILITY_LOST:
6527                    if (DBG && message.obj != null) log((String) message.obj);
6528                    handleIpReachabilityLost();
6529                    transitionTo(mDisconnectingState);
6530                    break;
6531                case CMD_DISCONNECT:
6532                    mWifiNative.disconnect();
6533                    transitionTo(mDisconnectingState);
6534                    break;
6535                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6536                    if (message.arg1 == 1) {
6537                        mWifiNative.disconnect();
6538                        mTemporarilyDisconnectWifi = true;
6539                        transitionTo(mDisconnectingState);
6540                    }
6541                    break;
6542                case CMD_SET_OPERATIONAL_MODE:
6543                    if (message.arg1 != CONNECT_MODE) {
6544                        sendMessage(CMD_DISCONNECT);
6545                        deferMessage(message);
6546                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6547                            noteWifiDisabledWhileAssociated();
6548                        }
6549                    }
6550                    mWifiConfigManager.
6551                                setAndEnableLastSelectedConfiguration(
6552                                        WifiConfiguration.INVALID_NETWORK_ID);
6553                    break;
6554                case CMD_START_SCAN:
6555                    if (DBG) {
6556                        logd("CMD_START_SCAN source " + message.arg1
6557                              + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
6558                              + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
6559                              + " targetRoamBSSID=" + mTargetRoamBSSID
6560                              + " RSSI=" + mWifiInfo.getRssi());
6561                    }
6562                    if (message.arg1 == SCAN_ALARM_SOURCE) {
6563                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
6564                        // not be processed) and restart the scan if neede
6565                        if (!mWifiConfigManager.getEnableAutoJoinWhenAssociated()) {
6566                            return HANDLED;
6567                        }
6568
6569                        if (mP2pConnected.get()) {
6570                            logd("L2Connected CMD_START_SCAN source "
6571                                    + message.arg1
6572                                    + " " + message.arg2 + ", "
6573                                    + " ignore because P2P is connected");
6574                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6575                            return HANDLED;
6576                        }
6577                        boolean tryFullBandScan = false;
6578                        boolean restrictChannelList = false;
6579                        long now_ms = System.currentTimeMillis();
6580                        if (DBG) {
6581                            logd("CMD_START_SCAN with age="
6582                                    + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
6583                                    + " interval=" + fullBandConnectedTimeIntervalMilli
6584                                    + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
6585                        }
6586
6587                        if (mWifiConfigManager.mEnableFullBandScanWhenAssociated.get()
6588                                && (now_ms - lastFullBandConnectedTimeMilli)
6589                                > fullBandConnectedTimeIntervalMilli) {
6590                            if (DBG) {
6591                                logd("CMD_START_SCAN try full band scan age="
6592                                         + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
6593                                         + " interval=" + fullBandConnectedTimeIntervalMilli
6594                                         + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
6595                            }
6596                            tryFullBandScan = true;
6597                        }
6598
6599                        if (mWifiInfo.txSuccessRate
6600                                        > mWifiConfigManager.MAX_TX_PACKET_FOR_FULL_SCANS
6601                                || mWifiInfo.rxSuccessRate
6602                                        > mWifiConfigManager.MAX_RX_PACKET_FOR_FULL_SCANS) {
6603                            // Too much traffic at the interface, hence no full band scan
6604                            if (DBG) {
6605                                logd("CMD_START_SCAN prevent full band scan due to pkt rate");
6606                            }
6607                            tryFullBandScan = false;
6608                        }
6609
6610                        if (mWifiInfo.txSuccessRate
6611                                        > mWifiConfigManager.MAX_TX_PACKET_FOR_PARTIAL_SCANS
6612                                || mWifiInfo.rxSuccessRate
6613                                        > mWifiConfigManager.MAX_RX_PACKET_FOR_PARTIAL_SCANS) {
6614                            // Don't scan if lots of packets are being sent
6615                            restrictChannelList = true;
6616                            if (mWifiConfigManager.mAlwaysEnableScansWhileAssociated.get() == 0) {
6617                                if (DBG) {
6618                                    logd("CMD_START_SCAN source " + message.arg1
6619                                            + " ...and ignore scans"
6620                                            + " tx="
6621                                            + String.format("%.2f", mWifiInfo.txSuccessRate)
6622                                            + " rx="
6623                                            + String.format("%.2f", mWifiInfo.rxSuccessRate));
6624                                }
6625                                messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
6626                                return HANDLED;
6627                            }
6628                        }
6629
6630                        WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
6631                        if (DBG) {
6632                            logd("CMD_START_SCAN full=" +
6633                                    tryFullBandScan);
6634                        }
6635                        if (currentConfiguration != null) {
6636                            if (fullBandConnectedTimeIntervalMilli <
6637                                    mWifiConfigManager.mWifiAssociatedShortScanIntervalMs.get()) {
6638                                // Sanity
6639                                fullBandConnectedTimeIntervalMilli =
6640                                        mWifiConfigManager
6641                                                .mWifiAssociatedShortScanIntervalMs.get();
6642                            }
6643                            if (tryFullBandScan) {
6644                                lastFullBandConnectedTimeMilli = now_ms;
6645                                if (fullBandConnectedTimeIntervalMilli
6646                                        < mWifiConfigManager.mAssociatedFullScanMaxIntervalMs) {
6647                                    // Increase the interval
6648                                    fullBandConnectedTimeIntervalMilli =
6649                                            fullBandConnectedTimeIntervalMilli *
6650                                                    mWifiConfigManager
6651                                                            .mAssociatedFullScanBackoff.get() / 8;
6652
6653                                    if (DBG) {
6654                                        logd("CMD_START_SCAN bump interval ="
6655                                        + fullBandConnectedTimeIntervalMilli);
6656                                    }
6657                                }
6658                                handleScanRequest(message);
6659                            } else {
6660                                if (!startScanForConfiguration(
6661                                        currentConfiguration, restrictChannelList)) {
6662                                    if (DBG) {
6663                                        logd("starting scan, " +
6664                                                " did not find channels -> full");
6665                                    }
6666                                    lastFullBandConnectedTimeMilli = now_ms;
6667                                    if (fullBandConnectedTimeIntervalMilli
6668                                            < mWifiConfigManager
6669                                            .mAssociatedFullScanMaxIntervalMs) {
6670                                        // Increase the interval
6671                                        fullBandConnectedTimeIntervalMilli =
6672                                                fullBandConnectedTimeIntervalMilli
6673                                                        * mWifiConfigManager
6674                                                                .mAssociatedFullScanBackoff.get()
6675                                                        / 8;
6676
6677                                        if (DBG) {
6678                                            logd("CMD_START_SCAN bump interval ="
6679                                                    + fullBandConnectedTimeIntervalMilli);
6680                                        }
6681                                    }
6682                                    handleScanRequest(message);
6683                                }
6684                            }
6685
6686                        } else {
6687                            logd("CMD_START_SCAN : connected mode and no configuration");
6688                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
6689                        }
6690                    } else {
6691                        // Not scan alarm source
6692                        return NOT_HANDLED;
6693                    }
6694                    break;
6695                    /* Ignore connection to same network */
6696                case WifiManager.CONNECT_NETWORK:
6697                    int netId = message.arg1;
6698                    if (mWifiInfo.getNetworkId() == netId) {
6699                        break;
6700                    }
6701                    return NOT_HANDLED;
6702                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6703                    mWifiInfo.setBSSID((String) message.obj);
6704                    mLastNetworkId = message.arg1;
6705                    mWifiInfo.setNetworkId(mLastNetworkId);
6706                    if(!mLastBssid.equals((String) message.obj)) {
6707                        mLastBssid = (String) message.obj;
6708                        sendNetworkStateChangeBroadcast(mLastBssid);
6709                    }
6710                    break;
6711                case CMD_RSSI_POLL:
6712                    if (message.arg1 == mRssiPollToken) {
6713                        if (mWifiConfigManager.mEnableChipWakeUpWhenAssociated.get()) {
6714                            if (DBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
6715                            WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
6716                            if (stats != null) {
6717                                // Sanity check the results provided by driver
6718                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
6719                                        && (stats.rssi_mgmt == 0
6720                                        || stats.beacon_rx == 0)) {
6721                                    stats = null;
6722                                }
6723                            }
6724                            // Get Info and continue polling
6725                            fetchRssiLinkSpeedAndFrequencyNative();
6726                            mWifiScoreReport =
6727                                    WifiScoreReport.calculateScore(mWifiInfo,
6728                                                                   getCurrentWifiConfiguration(),
6729                                                                   mWifiConfigManager,
6730                                                                   mNetworkAgent,
6731                                                                   mWifiScoreReport,
6732                                                                   mAggressiveHandover);
6733                        }
6734                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6735                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6736                        if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
6737                    } else {
6738                        // Polling has completed
6739                    }
6740                    break;
6741                case CMD_ENABLE_RSSI_POLL:
6742                    cleanWifiScore();
6743                    if (mWifiConfigManager.mEnableRssiPollWhenAssociated.get()) {
6744                        mEnableRssiPolling = (message.arg1 == 1);
6745                    } else {
6746                        mEnableRssiPolling = false;
6747                    }
6748                    mRssiPollToken++;
6749                    if (mEnableRssiPolling) {
6750                        // First poll
6751                        fetchRssiLinkSpeedAndFrequencyNative();
6752                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6753                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6754                    }
6755                    break;
6756                case WifiManager.RSSI_PKTCNT_FETCH:
6757                    RssiPacketCountInfo info = new RssiPacketCountInfo();
6758                    fetchRssiLinkSpeedAndFrequencyNative();
6759                    info.rssi = mWifiInfo.getRssi();
6760                    fetchPktcntNative(info);
6761                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
6762                    break;
6763                case CMD_DELAYED_NETWORK_DISCONNECT:
6764                    if (!linkDebouncing && mWifiConfigManager.mEnableLinkDebouncing) {
6765
6766                        // Ignore if we are not debouncing
6767                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
6768                                + message.arg1);
6769                        return HANDLED;
6770                    } else {
6771                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
6772                                + message.arg1);
6773
6774                        linkDebouncing = false;
6775                        // If we are still debouncing while this message comes,
6776                        // it means we were not able to reconnect within the alloted time
6777                        // = LINK_FLAPPING_DEBOUNCE_MSEC
6778                        // and thus, trigger a real disconnect
6779                        handleNetworkDisconnect();
6780                        transitionTo(mDisconnectedState);
6781                    }
6782                    break;
6783                case CMD_ASSOCIATED_BSSID:
6784                    if ((String) message.obj == null) {
6785                        logw("Associated command w/o BSSID");
6786                        break;
6787                    }
6788                    mLastBssid = (String) message.obj;
6789                    if (mLastBssid != null && (mWifiInfo.getBSSID() == null
6790                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
6791                        mWifiInfo.setBSSID((String) message.obj);
6792                        sendNetworkStateChangeBroadcast(mLastBssid);
6793                    }
6794                    break;
6795                case CMD_START_RSSI_MONITORING_OFFLOAD:
6796                case CMD_RSSI_THRESHOLD_BREACH:
6797                    byte currRssi = (byte) message.arg1;
6798                    processRssiThreshold(currRssi, message.what);
6799                    break;
6800                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
6801                    stopRssiMonitoringOffload();
6802                    break;
6803                case CMD_RESET_SIM_NETWORKS:
6804                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6805                        WifiConfiguration config =
6806                                mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6807                        if (mWifiConfigManager.isSimConfig(config)) {
6808                            mWifiNative.disconnect();
6809                            transitionTo(mDisconnectingState);
6810                        }
6811                    }
6812                    /* allow parent state to reset data for other networks */
6813                    return NOT_HANDLED;
6814                default:
6815                    return NOT_HANDLED;
6816            }
6817
6818            return HANDLED;
6819        }
6820    }
6821
6822    class ObtainingIpState extends State {
6823        @Override
6824        public void enter() {
6825            if (DBG) {
6826                String key = "";
6827                if (getCurrentWifiConfiguration() != null) {
6828                    key = getCurrentWifiConfiguration().configKey();
6829                }
6830                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
6831                        + " " + key + " "
6832                        + " roam=" + mAutoRoaming
6833                        + " static=" + mWifiConfigManager.isUsingStaticIp(mLastNetworkId)
6834                        + " watchdog= " + obtainingIpWatchdogCount);
6835            }
6836
6837            // Reset link Debouncing, indicating we have successfully re-connected to the AP
6838            // We might still be roaming
6839            linkDebouncing = false;
6840
6841            // Send event to CM & network change broadcast
6842            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
6843
6844            // We must clear the config BSSID, as the wifi chipset may decide to roam
6845            // from this point on and having the BSSID specified in the network block would
6846            // cause the roam to fail and the device to disconnect.
6847            clearCurrentConfigBSSID("ObtainingIpAddress");
6848
6849            // Stop IpManager in case we're switching from DHCP to static
6850            // configuration or vice versa.
6851            //
6852            // TODO: Only ever enter this state the first time we connect to a
6853            // network, never on switching between static configuration and
6854            // DHCP. When we transition from static configuration to DHCP in
6855            // particular, we must tell ConnectivityService that we're
6856            // disconnected, because DHCP might take a long time during which
6857            // connectivity APIs such as getActiveNetworkInfo should not return
6858            // CONNECTED.
6859            stopIpManager();
6860
6861            mIpManager.setHttpProxy(mWifiConfigManager.getProxyProperties(mLastNetworkId));
6862            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
6863                mIpManager.setTcpBufferSizes(mTcpBufferSizes);
6864            }
6865
6866            if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
6867                final IpManager.ProvisioningConfiguration prov =
6868                        mIpManager.buildProvisioningConfiguration()
6869                            .withPreDhcpAction()
6870                            .withApfCapabilities(mWifiNative.getApfCapabilities())
6871                            .build();
6872                mIpManager.startProvisioning(prov);
6873                obtainingIpWatchdogCount++;
6874                logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
6875                // Get Link layer stats so as we get fresh tx packet counters
6876                getWifiLinkLayerStats(true);
6877                sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
6878                        obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
6879            } else {
6880                StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(
6881                        mLastNetworkId);
6882                if (config.ipAddress == null) {
6883                    logd("Static IP lacks address");
6884                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
6885                } else {
6886                    final IpManager.ProvisioningConfiguration prov =
6887                            mIpManager.buildProvisioningConfiguration()
6888                                .withStaticConfiguration(config)
6889                                .withApfCapabilities(mWifiNative.getApfCapabilities())
6890                                .build();
6891                    mIpManager.startProvisioning(prov);
6892                }
6893            }
6894        }
6895
6896        @Override
6897        public boolean processMessage(Message message) {
6898            logStateAndMessage(message, this);
6899
6900            switch(message.what) {
6901                case CMD_AUTO_CONNECT:
6902                case CMD_AUTO_ROAM:
6903                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6904                    break;
6905                case WifiManager.SAVE_NETWORK:
6906                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
6907                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6908                    deferMessage(message);
6909                    break;
6910                    /* Defer any power mode changes since we must keep active power mode at DHCP */
6911
6912                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6913                    reportConnectionAttemptEnd(
6914                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6915                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6916                    return NOT_HANDLED;
6917                case CMD_SET_HIGH_PERF_MODE:
6918                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6919                    deferMessage(message);
6920                    break;
6921                    /* Defer scan request since we should not switch to other channels at DHCP */
6922                case CMD_START_SCAN:
6923                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6924                    deferMessage(message);
6925                    break;
6926                case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
6927                    if (message.arg1 == obtainingIpWatchdogCount) {
6928                        logd("ObtainingIpAddress: Watchdog Triggered, count="
6929                                + obtainingIpWatchdogCount);
6930                        handleIpConfigurationLost();
6931                        transitionTo(mDisconnectingState);
6932                        break;
6933                    }
6934                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6935                    break;
6936                default:
6937                    return NOT_HANDLED;
6938            }
6939            return HANDLED;
6940        }
6941    }
6942
6943    private void sendConnectedState() {
6944        // If this network was explicitly selected by the user, evaluate whether to call
6945        // explicitlySelected() so the system can treat it appropriately.
6946        WifiConfiguration config = getCurrentWifiConfiguration();
6947        if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
6948            boolean prompt =
6949                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
6950            if (DBG) {
6951                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
6952            }
6953            if (prompt) {
6954                // Selected by the user via Settings or QuickSettings. If this network has Internet
6955                // access, switch to it. Otherwise, switch to it only if the user confirms that they
6956                // really want to switch, or has already confirmed and selected "Don't ask again".
6957                if (DBG) {
6958                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
6959                }
6960                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
6961            }
6962        }
6963
6964        setNetworkDetailedState(DetailedState.CONNECTED);
6965        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
6966        sendNetworkStateChangeBroadcast(mLastBssid);
6967    }
6968
6969    class RoamingState extends State {
6970        boolean mAssociated;
6971        @Override
6972        public void enter() {
6973            if (DBG) {
6974                log("RoamingState Enter"
6975                        + " mScreenOn=" + mScreenOn );
6976            }
6977
6978            // Make sure we disconnect if roaming fails
6979            roamWatchdogCount++;
6980            logd("Start Roam Watchdog " + roamWatchdogCount);
6981            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
6982                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
6983            mAssociated = false;
6984        }
6985        @Override
6986        public boolean processMessage(Message message) {
6987            logStateAndMessage(message, this);
6988            WifiConfiguration config;
6989            switch (message.what) {
6990                case CMD_IP_CONFIGURATION_LOST:
6991                    config = getCurrentWifiConfiguration();
6992                    if (config != null) {
6993                        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
6994                        mWifiConfigManager.noteRoamingFailure(config,
6995                                WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
6996                    }
6997                    return NOT_HANDLED;
6998                case CMD_UNWANTED_NETWORK:
6999                    if (DBG) log("Roaming and CS doesnt want the network -> ignore");
7000                    return HANDLED;
7001                case CMD_SET_OPERATIONAL_MODE:
7002                    if (message.arg1 != CONNECT_MODE) {
7003                        deferMessage(message);
7004                    }
7005                    break;
7006                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7007                    /**
7008                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
7009                     * before NETWORK_DISCONNECTION_EVENT
7010                     * And there is an associated BSSID corresponding to our target BSSID, then
7011                     * we have missed the network disconnection, transition to mDisconnectedState
7012                     * and handle the rest of the events there.
7013                     */
7014                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7015                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
7016                            || stateChangeResult.state == SupplicantState.INACTIVE
7017                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
7018                        if (DBG) {
7019                            log("STATE_CHANGE_EVENT in roaming state "
7020                                    + stateChangeResult.toString() );
7021                        }
7022                        if (stateChangeResult.BSSID != null
7023                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
7024                            handleNetworkDisconnect();
7025                            transitionTo(mDisconnectedState);
7026                        }
7027                    }
7028                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
7029                        // We completed the layer2 roaming part
7030                        mAssociated = true;
7031                        if (stateChangeResult.BSSID != null) {
7032                            mTargetRoamBSSID = (String) stateChangeResult.BSSID;
7033                        }
7034                    }
7035                    break;
7036                case CMD_ROAM_WATCHDOG_TIMER:
7037                    if (roamWatchdogCount == message.arg1) {
7038                        if (DBG) log("roaming watchdog! -> disconnect");
7039                        mWifiMetrics.endConnectionEvent(
7040                                WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
7041                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7042                        mRoamFailCount++;
7043                        handleNetworkDisconnect();
7044                        mWifiNative.disconnect();
7045                        transitionTo(mDisconnectedState);
7046                    }
7047                    break;
7048                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7049                    if (mAssociated) {
7050                        if (DBG) log("roaming and Network connection established");
7051                        mLastNetworkId = message.arg1;
7052                        mLastBssid = (String) message.obj;
7053                        mWifiInfo.setBSSID(mLastBssid);
7054                        mWifiInfo.setNetworkId(mLastNetworkId);
7055                        if (mWifiConnectivityManager != null) {
7056                            mWifiConnectivityManager.trackBssid(mLastBssid, true);
7057                        }
7058                        sendNetworkStateChangeBroadcast(mLastBssid);
7059
7060                        // Successful framework roam! (probably)
7061                        reportConnectionAttemptEnd(
7062                                WifiMetrics.ConnectionEvent.FAILURE_NONE,
7063                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7064                        // We used to transition to ObtainingIpState in an
7065                        // attempt to do DHCPv4 RENEWs on framework roams.
7066                        // DHCP can take too long to time out, and we now rely
7067                        // upon IpManager's use of IpReachabilityMonitor to
7068                        // confirm our current network configuration.
7069                        //
7070                        // mIpManager.confirmConfiguration() is called within
7071                        // the handling of SupplicantState.COMPLETED.
7072                        transitionTo(mConnectedState);
7073                    } else {
7074                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7075                    }
7076                    break;
7077                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7078                    // Throw away but only if it corresponds to the network we're roaming to
7079                    String bssid = (String) message.obj;
7080                    if (true) {
7081                        String target = "";
7082                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
7083                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
7084                                + " BSSID=" + bssid
7085                                + " target=" + target);
7086                    }
7087                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
7088                        handleNetworkDisconnect();
7089                        transitionTo(mDisconnectedState);
7090                    }
7091                    break;
7092                case WifiMonitor.SSID_TEMP_DISABLED:
7093                    // Auth error while roaming
7094                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
7095                            + " id=" + Integer.toString(message.arg1)
7096                            + " isRoaming=" + isRoaming()
7097                            + " roam=" + mAutoRoaming);
7098                    if (message.arg1 == mLastNetworkId) {
7099                        config = getCurrentWifiConfiguration();
7100                        if (config != null) {
7101                            mWifiLogger.captureBugReportData(
7102                                    WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
7103                            mWifiConfigManager.noteRoamingFailure(config,
7104                                    WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
7105                        }
7106                        handleNetworkDisconnect();
7107                        transitionTo(mDisconnectingState);
7108                    }
7109                    return NOT_HANDLED;
7110                case CMD_START_SCAN:
7111                    deferMessage(message);
7112                    break;
7113                default:
7114                    return NOT_HANDLED;
7115            }
7116            return HANDLED;
7117        }
7118
7119        @Override
7120        public void exit() {
7121            logd("WifiStateMachine: Leaving Roaming state");
7122        }
7123    }
7124
7125    class ConnectedState extends State {
7126        @Override
7127        public void enter() {
7128            String address;
7129            updateDefaultRouteMacAddress(1000);
7130            if (DBG) {
7131                log("Enter ConnectedState "
7132                       + " mScreenOn=" + mScreenOn
7133                       + " scanperiod="
7134                       + Integer.toString(
7135                            mWifiConfigManager.mWifiAssociatedShortScanIntervalMs.get()));
7136            }
7137
7138            if (mWifiConnectivityManager != null) {
7139                mWifiConnectivityManager.handleConnectionStateChanged(
7140                        WifiConnectivityManager.WIFI_STATE_CONNECTED);
7141            }
7142            registerConnected();
7143            lastConnectAttemptTimestamp = 0;
7144            targetWificonfiguration = null;
7145            // Paranoia
7146            linkDebouncing = false;
7147
7148            // Not roaming anymore
7149            mAutoRoaming = false;
7150
7151            if (testNetworkDisconnect) {
7152                testNetworkDisconnectCounter++;
7153                logd("ConnectedState Enter start disconnect test " +
7154                        testNetworkDisconnectCounter);
7155                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
7156                        testNetworkDisconnectCounter, 0), 15000);
7157            }
7158
7159            // Reenable all networks, allow for hidden networks to be scanned
7160            mWifiConfigManager.enableAllNetworks();
7161
7162            mLastDriverRoamAttempt = 0;
7163            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
7164        }
7165        @Override
7166        public boolean processMessage(Message message) {
7167            WifiConfiguration config = null;
7168            logStateAndMessage(message, this);
7169
7170            switch (message.what) {
7171                case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
7172                    updateAssociatedScanPermission();
7173                    break;
7174                case CMD_UNWANTED_NETWORK:
7175                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
7176                        mWifiConfigManager.handleBadNetworkDisconnectReport(
7177                                mLastNetworkId, mWifiInfo);
7178                        mWifiNative.disconnect();
7179                        transitionTo(mDisconnectingState);
7180                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
7181                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
7182                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
7183                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
7184                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
7185                        config = getCurrentWifiConfiguration();
7186                        if (config != null) {
7187                            // Disable autojoin
7188                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
7189                                config.validatedInternetAccess = false;
7190                                // Clear last-selected status, as being last-selected also avoids
7191                                // disabling auto-join.
7192                                if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
7193                                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(
7194                                        WifiConfiguration.INVALID_NETWORK_ID);
7195                                }
7196                                mWifiConfigManager.updateNetworkSelectionStatus(config,
7197                                        WifiConfiguration.NetworkSelectionStatus
7198                                        .DISABLED_NO_INTERNET);
7199                            }
7200                            config.numNoInternetAccessReports += 1;
7201                            mWifiConfigManager.writeKnownNetworkHistory();
7202                        }
7203                    }
7204                    return HANDLED;
7205                case CMD_NETWORK_STATUS:
7206                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
7207                        config = getCurrentWifiConfiguration();
7208                        if (config != null) {
7209                            // re-enable autojoin
7210                            config.numNoInternetAccessReports = 0;
7211                            config.validatedInternetAccess = true;
7212                            mWifiConfigManager.writeKnownNetworkHistory();
7213                        }
7214                    }
7215                    return HANDLED;
7216                case CMD_ACCEPT_UNVALIDATED:
7217                    boolean accept = (message.arg1 != 0);
7218                    config = getCurrentWifiConfiguration();
7219                    if (config != null) {
7220                        config.noInternetAccessExpected = accept;
7221                    }
7222                    return HANDLED;
7223                case CMD_TEST_NETWORK_DISCONNECT:
7224                    // Force a disconnect
7225                    if (message.arg1 == testNetworkDisconnectCounter) {
7226                        mWifiNative.disconnect();
7227                    }
7228                    break;
7229                case CMD_ASSOCIATED_BSSID:
7230                    // ASSOCIATING to a new BSSID while already connected, indicates
7231                    // that driver is roaming
7232                    mLastDriverRoamAttempt = System.currentTimeMillis();
7233                    return NOT_HANDLED;
7234                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7235                    long lastRoam = 0;
7236                    reportConnectionAttemptEnd(
7237                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
7238                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
7239                    if (mLastDriverRoamAttempt != 0) {
7240                        // Calculate time since last driver roam attempt
7241                        lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
7242                        mLastDriverRoamAttempt = 0;
7243                    }
7244                    if (unexpectedDisconnectedReason(message.arg2)) {
7245                        mWifiLogger.captureBugReportData(
7246                                WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
7247                    }
7248                    config = getCurrentWifiConfiguration();
7249                    if (mScreenOn
7250                            && !linkDebouncing
7251                            && config != null
7252                            && config.getNetworkSelectionStatus().isNetworkEnabled()
7253                            && !mWifiConfigManager.isLastSelectedConfiguration(config)
7254                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
7255                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
7256                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
7257                                    && mWifiInfo.getRssi() >
7258                                    WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
7259                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
7260                                    && mWifiInfo.getRssi() >
7261                                    mWifiConfigManager.mThresholdQualifiedRssi5.get()))) {
7262                        // Start de-bouncing the L2 disconnection:
7263                        // this L2 disconnection might be spurious.
7264                        // Hence we allow 4 seconds for the state machine to try
7265                        // to reconnect, go thru the
7266                        // roaming cycle and enter Obtaining IP address
7267                        // before signalling the disconnect to ConnectivityService and L3
7268                        startScanForConfiguration(getCurrentWifiConfiguration(), false);
7269                        linkDebouncing = true;
7270
7271                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
7272                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
7273                        if (DBG) {
7274                            log("NETWORK_DISCONNECTION_EVENT in connected state"
7275                                    + " BSSID=" + mWifiInfo.getBSSID()
7276                                    + " RSSI=" + mWifiInfo.getRssi()
7277                                    + " freq=" + mWifiInfo.getFrequency()
7278                                    + " reason=" + message.arg2
7279                                    + " -> debounce");
7280                        }
7281                        return HANDLED;
7282                    } else {
7283                        if (DBG) {
7284                            log("NETWORK_DISCONNECTION_EVENT in connected state"
7285                                    + " BSSID=" + mWifiInfo.getBSSID()
7286                                    + " RSSI=" + mWifiInfo.getRssi()
7287                                    + " freq=" + mWifiInfo.getFrequency()
7288                                    + " was debouncing=" + linkDebouncing
7289                                    + " reason=" + message.arg2
7290                                    + " Network Selection Status=" + (config == null ? "Unavailable"
7291                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
7292                        }
7293                    }
7294                    break;
7295                case CMD_AUTO_ROAM:
7296                    // Clear the driver roam indication since we are attempting a framework roam
7297                    mLastDriverRoamAttempt = 0;
7298
7299                    /*<TODO> 2016-02-24
7300                        Fix CMD_AUTO_ROAM to use the candidate (message.arg1) networkID, rather than
7301                        the old networkID.
7302                        The current code only handles roaming between BSSIDs on the same networkID,
7303                        and will break for roams between different (but linked) networkIDs. This
7304                        case occurs for DBDC roaming, and the CMD_AUTO_ROAM sent due to it will
7305                        fail.
7306                    */
7307                    /* Connect command coming from auto-join */
7308                    ScanResult candidate = (ScanResult)message.obj;
7309                    String bssid = "any";
7310                    if (candidate != null) {
7311                        bssid = candidate.BSSID;
7312                    }
7313                    int netId = message.arg1;
7314                    if (netId == WifiConfiguration.INVALID_NETWORK_ID) {
7315                        loge("AUTO_ROAM and no config, bail out...");
7316                        break;
7317                    } else {
7318                        config = mWifiConfigManager.getWifiConfiguration(netId);
7319                    }
7320
7321                    logd("CMD_AUTO_ROAM sup state "
7322                            + mSupplicantStateTracker.getSupplicantStateName()
7323                            + " my state " + getCurrentState().getName()
7324                            + " nid=" + Integer.toString(netId)
7325                            + " config " + config.configKey()
7326                            + " roam=" + Integer.toString(message.arg2)
7327                            + " to " + bssid
7328                            + " targetRoamBSSID " + mTargetRoamBSSID);
7329
7330                    setTargetBssid(config, bssid);
7331                    mTargetNetworkId = netId;
7332
7333                    /* Determine if this is a regular roam (between BSSIDs sharing the same SSID),
7334                       or a DBDC roam (between 2.4 & 5GHz networks on different SSID's, but with
7335                       matching 16 byte BSSID prefixes):
7336                     */
7337                    WifiConfiguration currentConfig = getCurrentWifiConfiguration();
7338                    if (currentConfig != null && currentConfig.isLinked(config)) {
7339                        // This is dual band roaming
7340                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
7341                                WifiMetricsProto.ConnectionEvent.ROAM_DBDC);
7342                    } else {
7343                        // This is regular roaming
7344                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
7345                                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
7346                    }
7347
7348                    if (deferForUserInput(message, netId, false)) {
7349                        reportConnectionAttemptEnd(
7350                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7351                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7352                        break;
7353                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
7354                            WifiConfiguration.USER_BANNED) {
7355                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7356                                WifiManager.NOT_AUTHORIZED);
7357                        reportConnectionAttemptEnd(
7358                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7359                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7360                        break;
7361                    }
7362
7363                    boolean ret = false;
7364                    if (mLastNetworkId != netId) {
7365                        if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
7366                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
7367                            ret = true;
7368                        }
7369                    } else {
7370                        ret = mWifiNative.reassociate();
7371                    }
7372                    if (ret) {
7373                        lastConnectAttemptTimestamp = System.currentTimeMillis();
7374                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
7375
7376                        // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
7377                        mAutoRoaming = true;
7378                        transitionTo(mRoamingState);
7379
7380                    } else {
7381                        loge("Failed to connect config: " + config + " netId: " + netId);
7382                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7383                                WifiManager.ERROR);
7384                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7385                        reportConnectionAttemptEnd(
7386                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7387                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7388                        break;
7389                    }
7390                    break;
7391                case CMD_START_IP_PACKET_OFFLOAD: {
7392                        int slot = message.arg1;
7393                        int intervalSeconds = message.arg2;
7394                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
7395                        byte[] dstMac;
7396                        try {
7397                            InetAddress gateway = RouteInfo.selectBestRoute(
7398                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
7399                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
7400                            dstMac = macAddressFromString(dstMacStr);
7401                        } catch (NullPointerException|IllegalArgumentException e) {
7402                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
7403                            mNetworkAgent.onPacketKeepaliveEvent(slot,
7404                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
7405                            break;
7406                        }
7407                        pkt.dstMac = dstMac;
7408                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
7409                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
7410                        break;
7411                    }
7412                default:
7413                    return NOT_HANDLED;
7414            }
7415            return HANDLED;
7416        }
7417
7418        @Override
7419        public void exit() {
7420            logd("WifiStateMachine: Leaving Connected state");
7421            if (mWifiConnectivityManager != null) {
7422                mWifiConnectivityManager.handleConnectionStateChanged(
7423                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7424            }
7425
7426            mLastDriverRoamAttempt = 0;
7427            mWhiteListedSsids = null;
7428        }
7429    }
7430
7431    class DisconnectingState extends State {
7432
7433        @Override
7434        public void enter() {
7435
7436            if (DBG) {
7437                logd(" Enter DisconnectingState State scan interval "
7438                        + mWifiConfigManager.mWifiDisconnectedShortScanIntervalMs.get()
7439                        + " screenOn=" + mScreenOn);
7440            }
7441
7442            // Make sure we disconnect: we enter this state prior to connecting to a new
7443            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
7444            // event which in this case will be indicating that supplicant started to associate.
7445            // In some cases supplicant doesn't ignore the connect requests (it might not
7446            // find the target SSID in its cache),
7447            // Therefore we end up stuck that state, hence the need for the watchdog.
7448            disconnectingWatchdogCount++;
7449            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
7450            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
7451                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
7452        }
7453
7454        @Override
7455        public boolean processMessage(Message message) {
7456            logStateAndMessage(message, this);
7457            switch (message.what) {
7458                case CMD_SET_OPERATIONAL_MODE:
7459                    if (message.arg1 != CONNECT_MODE) {
7460                        deferMessage(message);
7461                    }
7462                    break;
7463                case CMD_START_SCAN:
7464                    deferMessage(message);
7465                    return HANDLED;
7466                case CMD_DISCONNECTING_WATCHDOG_TIMER:
7467                    if (disconnectingWatchdogCount == message.arg1) {
7468                        if (DBG) log("disconnecting watchdog! -> disconnect");
7469                        handleNetworkDisconnect();
7470                        transitionTo(mDisconnectedState);
7471                    }
7472                    break;
7473                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7474                    /**
7475                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
7476                     * we have missed the network disconnection, transition to mDisconnectedState
7477                     * and handle the rest of the events there
7478                     */
7479                    deferMessage(message);
7480                    handleNetworkDisconnect();
7481                    transitionTo(mDisconnectedState);
7482                    break;
7483                default:
7484                    return NOT_HANDLED;
7485            }
7486            return HANDLED;
7487        }
7488    }
7489
7490    class DisconnectedState extends State {
7491        @Override
7492        public void enter() {
7493            // We dont scan frequently if this is a temporary disconnect
7494            // due to p2p
7495            if (mTemporarilyDisconnectWifi) {
7496                mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
7497                return;
7498            }
7499
7500            if (DBG) {
7501                logd(" Enter DisconnectedState scan interval "
7502                        + mWifiConfigManager.mWifiDisconnectedShortScanIntervalMs.get()
7503                        + " screenOn=" + mScreenOn);
7504            }
7505
7506            /** clear the roaming state, if we were roaming, we failed */
7507            mAutoRoaming = false;
7508
7509            if (mWifiConnectivityManager != null) {
7510                mWifiConnectivityManager.handleConnectionStateChanged(
7511                        WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
7512            }
7513
7514            /**
7515             * If we have no networks saved, the supplicant stops doing the periodic scan.
7516             * The scans are useful to notify the user of the presence of an open network.
7517             * Note that these are not wake up scans.
7518             */
7519            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
7520                    && mWifiConfigManager.getSavedNetworks().size() == 0) {
7521                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7522                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7523            }
7524
7525            mDisconnectedTimeStamp = System.currentTimeMillis();
7526        }
7527        @Override
7528        public boolean processMessage(Message message) {
7529            boolean ret = HANDLED;
7530
7531            logStateAndMessage(message, this);
7532
7533            switch (message.what) {
7534                case CMD_NO_NETWORKS_PERIODIC_SCAN:
7535                    if (mP2pConnected.get()) break;
7536                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
7537                            mWifiConfigManager.getSavedNetworks().size() == 0) {
7538                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, WIFI_WORK_SOURCE);
7539                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7540                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7541                    }
7542                    break;
7543                case WifiManager.FORGET_NETWORK:
7544                case CMD_REMOVE_NETWORK:
7545                case CMD_REMOVE_APP_CONFIGURATIONS:
7546                case CMD_REMOVE_USER_CONFIGURATIONS:
7547                    // Set up a delayed message here. After the forget/remove is handled
7548                    // the handled delayed message will determine if there is a need to
7549                    // scan and continue
7550                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7551                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7552                    ret = NOT_HANDLED;
7553                    break;
7554                case CMD_SET_OPERATIONAL_MODE:
7555                    if (message.arg1 != CONNECT_MODE) {
7556                        mOperationalMode = message.arg1;
7557                        mWifiConfigManager.disableAllNetworksNative();
7558                        if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
7559                            mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
7560                            setWifiState(WIFI_STATE_DISABLED);
7561                        }
7562                        transitionTo(mScanModeState);
7563                    }
7564                    mWifiConfigManager.
7565                            setAndEnableLastSelectedConfiguration(
7566                                    WifiConfiguration.INVALID_NETWORK_ID);
7567                    break;
7568                    /* Ignore network disconnect */
7569                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7570                    // Interpret this as an L2 connection failure
7571                    break;
7572                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7573                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7574                    if (DBG) {
7575                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
7576                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
7577                                + " debouncing=" + linkDebouncing);
7578                    }
7579                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
7580                    /* ConnectModeState does the rest of the handling */
7581                    ret = NOT_HANDLED;
7582                    break;
7583                case CMD_START_SCAN:
7584                    if (!checkOrDeferScanAllowed(message)) {
7585                        // The scan request was rescheduled
7586                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
7587                        return HANDLED;
7588                    }
7589                    if (message.arg1 == SCAN_ALARM_SOURCE) {
7590                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
7591                        // not be processed) and restart the scan
7592                        int period =
7593                                mWifiConfigManager.mWifiDisconnectedShortScanIntervalMs.get();
7594                        if (mP2pConnected.get()) {
7595                            period = (int) mFacade.getLongSetting(mContext,
7596                                    Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
7597                                    period);
7598                        }
7599
7600                        handleScanRequest(message);
7601                        ret = HANDLED;
7602                    } else {
7603                        ret = NOT_HANDLED;
7604                    }
7605                    break;
7606                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
7607                    NetworkInfo info = (NetworkInfo) message.obj;
7608                    mP2pConnected.set(info.isConnected());
7609                    if (mP2pConnected.get()) {
7610                        int defaultInterval = mContext.getResources().getInteger(
7611                                R.integer.config_wifi_scan_interval_p2p_connected);
7612                        long scanIntervalMs = mFacade.getLongSetting(mContext,
7613                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
7614                                defaultInterval);
7615                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
7616                    } else if (mWifiConfigManager.getSavedNetworks().size() == 0) {
7617                        if (DBG) log("Turn on scanning after p2p disconnected");
7618                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7619                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7620                    }
7621                    break;
7622                case CMD_RECONNECT:
7623                case CMD_REASSOCIATE:
7624                    if (mTemporarilyDisconnectWifi) {
7625                        // Drop a third party reconnect/reassociate if STA is
7626                        // temporarily disconnected for p2p
7627                        break;
7628                    } else {
7629                        // ConnectModeState handles it
7630                        ret = NOT_HANDLED;
7631                    }
7632                    break;
7633                case CMD_SCREEN_STATE_CHANGED:
7634                    handleScreenStateChanged(message.arg1 != 0);
7635                    break;
7636                default:
7637                    ret = NOT_HANDLED;
7638            }
7639            return ret;
7640        }
7641
7642        @Override
7643        public void exit() {
7644            if (mWifiConnectivityManager != null) {
7645                mWifiConnectivityManager.handleConnectionStateChanged(
7646                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7647            }
7648        }
7649    }
7650
7651    class WpsRunningState extends State {
7652        // Tracks the source to provide a reply
7653        private Message mSourceMessage;
7654        @Override
7655        public void enter() {
7656            mSourceMessage = Message.obtain(getCurrentMessage());
7657        }
7658        @Override
7659        public boolean processMessage(Message message) {
7660            logStateAndMessage(message, this);
7661
7662            switch (message.what) {
7663                case WifiMonitor.WPS_SUCCESS_EVENT:
7664                    // Ignore intermediate success, wait for full connection
7665                    break;
7666                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7667                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
7668                    mSourceMessage.recycle();
7669                    mSourceMessage = null;
7670                    deferMessage(message);
7671                    transitionTo(mDisconnectedState);
7672                    break;
7673                case WifiMonitor.WPS_OVERLAP_EVENT:
7674                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7675                            WifiManager.WPS_OVERLAP_ERROR);
7676                    mSourceMessage.recycle();
7677                    mSourceMessage = null;
7678                    transitionTo(mDisconnectedState);
7679                    break;
7680                case WifiMonitor.WPS_FAIL_EVENT:
7681                    // Arg1 has the reason for the failure
7682                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
7683                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
7684                        mSourceMessage.recycle();
7685                        mSourceMessage = null;
7686                        transitionTo(mDisconnectedState);
7687                    } else {
7688                        if (DBG) log("Ignore unspecified fail event during WPS connection");
7689                    }
7690                    break;
7691                case WifiMonitor.WPS_TIMEOUT_EVENT:
7692                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7693                            WifiManager.WPS_TIMED_OUT);
7694                    mSourceMessage.recycle();
7695                    mSourceMessage = null;
7696                    transitionTo(mDisconnectedState);
7697                    break;
7698                case WifiManager.START_WPS:
7699                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
7700                    break;
7701                case WifiManager.CANCEL_WPS:
7702                    if (mWifiNative.cancelWps()) {
7703                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
7704                    } else {
7705                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
7706                    }
7707                    transitionTo(mDisconnectedState);
7708                    break;
7709                /**
7710                 * Defer all commands that can cause connections to a different network
7711                 * or put the state machine out of connect mode
7712                 */
7713                case CMD_STOP_DRIVER:
7714                case CMD_SET_OPERATIONAL_MODE:
7715                case WifiManager.CONNECT_NETWORK:
7716                case CMD_ENABLE_NETWORK:
7717                case CMD_RECONNECT:
7718                case CMD_REASSOCIATE:
7719                case CMD_ENABLE_ALL_NETWORKS:
7720                    deferMessage(message);
7721                    break;
7722                case CMD_AUTO_CONNECT:
7723                case CMD_AUTO_ROAM:
7724                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7725                    return HANDLED;
7726                case CMD_START_SCAN:
7727                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7728                    return HANDLED;
7729                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7730                    if (DBG) log("Network connection lost");
7731                    handleNetworkDisconnect();
7732                    break;
7733                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
7734                    if (DBG) log("Ignore Assoc reject event during WPS Connection");
7735                    break;
7736                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
7737                    // Disregard auth failure events during WPS connection. The
7738                    // EAP sequence is retried several times, and there might be
7739                    // failures (especially for wps pin). We will get a WPS_XXX
7740                    // event at the end of the sequence anyway.
7741                    if (DBG) log("Ignore auth failure during WPS connection");
7742                    break;
7743                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7744                    // Throw away supplicant state changes when WPS is running.
7745                    // We will start getting supplicant state changes once we get
7746                    // a WPS success or failure
7747                    break;
7748                default:
7749                    return NOT_HANDLED;
7750            }
7751            return HANDLED;
7752        }
7753
7754        @Override
7755        public void exit() {
7756            mWifiConfigManager.enableAllNetworks();
7757            mWifiConfigManager.loadConfiguredNetworks();
7758        }
7759    }
7760
7761    class SoftApState extends State {
7762        private SoftApManager mSoftApManager;
7763
7764        private class SoftApListener implements SoftApManager.Listener {
7765            @Override
7766            public void onStateChanged(int state, int reason) {
7767                if (state == WIFI_AP_STATE_DISABLED) {
7768                    sendMessage(CMD_AP_STOPPED);
7769                } else if (state == WIFI_AP_STATE_FAILED) {
7770                    sendMessage(CMD_START_AP_FAILURE);
7771                }
7772
7773                setWifiApState(state, reason);
7774            }
7775        }
7776
7777        @Override
7778        public void enter() {
7779            final Message message = getCurrentMessage();
7780            if (message.what == CMD_START_AP) {
7781                WifiConfiguration config = (WifiConfiguration) message.obj;
7782
7783                if (config == null) {
7784                    /**
7785                     * Configuration not provided in the command, fallback to use the current
7786                     * configuration.
7787                     */
7788                    config = mWifiApConfigStore.getApConfiguration();
7789                } else {
7790                    /* Update AP configuration. */
7791                    mWifiApConfigStore.setApConfiguration(config);
7792                }
7793
7794                checkAndSetConnectivityInstance();
7795                mSoftApManager = mFacade.makeSoftApManager(
7796                        mContext, getHandler().getLooper(), mWifiNative, mNwService,
7797                        mCm, mCountryCode.getCurrentCountryCode(),
7798                        mWifiApConfigStore.getAllowed2GChannel(),
7799                        new SoftApListener());
7800                mSoftApManager.start(config);
7801            } else {
7802                throw new RuntimeException("Illegal transition to SoftApState: " + message);
7803            }
7804        }
7805
7806        @Override
7807        public void exit() {
7808            mSoftApManager = null;
7809        }
7810
7811        @Override
7812        public boolean processMessage(Message message) {
7813            logStateAndMessage(message, this);
7814
7815            switch(message.what) {
7816                case CMD_START_AP:
7817                    /* Ignore start command when it is starting/started. */
7818                    break;
7819                case CMD_STOP_AP:
7820                    mSoftApManager.stop();
7821                    break;
7822                case CMD_START_AP_FAILURE:
7823                    transitionTo(mInitialState);
7824                    break;
7825                case CMD_AP_STOPPED:
7826                    transitionTo(mInitialState);
7827                    break;
7828                default:
7829                    return NOT_HANDLED;
7830            }
7831            return HANDLED;
7832        }
7833    }
7834
7835    /**
7836     * State machine initiated requests can have replyTo set to null indicating
7837     * there are no recepients, we ignore those reply actions.
7838     */
7839    private void replyToMessage(Message msg, int what) {
7840        if (msg.replyTo == null) return;
7841        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7842        mReplyChannel.replyToMessage(msg, dstMsg);
7843    }
7844
7845    private void replyToMessage(Message msg, int what, int arg1) {
7846        if (msg.replyTo == null) return;
7847        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7848        dstMsg.arg1 = arg1;
7849        mReplyChannel.replyToMessage(msg, dstMsg);
7850    }
7851
7852    private void replyToMessage(Message msg, int what, Object obj) {
7853        if (msg.replyTo == null) return;
7854        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7855        dstMsg.obj = obj;
7856        mReplyChannel.replyToMessage(msg, dstMsg);
7857    }
7858
7859    /**
7860     * arg2 on the source message has a unique id that needs to be retained in replies
7861     * to match the request
7862     * <p>see WifiManager for details
7863     */
7864    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
7865        Message msg = Message.obtain();
7866        msg.what = what;
7867        msg.arg2 = srcMsg.arg2;
7868        return msg;
7869    }
7870
7871    /**
7872     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
7873     * @param msg Must have a WifiConfiguration obj to succeed
7874     */
7875    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
7876            WifiConfiguration config) {
7877        if (config != null && config.preSharedKey != null) {
7878            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
7879            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
7880            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
7881                    wifiCredentialEventType);
7882            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
7883                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
7884        }
7885    }
7886
7887    private static int parseHex(char ch) {
7888        if ('0' <= ch && ch <= '9') {
7889            return ch - '0';
7890        } else if ('a' <= ch && ch <= 'f') {
7891            return ch - 'a' + 10;
7892        } else if ('A' <= ch && ch <= 'F') {
7893            return ch - 'A' + 10;
7894        } else {
7895            throw new NumberFormatException("" + ch + " is not a valid hex digit");
7896        }
7897    }
7898
7899    private byte[] parseHex(String hex) {
7900        /* This only works for good input; don't throw bad data at it */
7901        if (hex == null) {
7902            return new byte[0];
7903        }
7904
7905        if (hex.length() % 2 != 0) {
7906            throw new NumberFormatException(hex + " is not a valid hex string");
7907        }
7908
7909        byte[] result = new byte[(hex.length())/2 + 1];
7910        result[0] = (byte) ((hex.length())/2);
7911        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
7912            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
7913            byte b = (byte) (val & 0xFF);
7914            result[j] = b;
7915        }
7916
7917        return result;
7918    }
7919
7920    private static String makeHex(byte[] bytes) {
7921        StringBuilder sb = new StringBuilder();
7922        for (byte b : bytes) {
7923            sb.append(String.format("%02x", b));
7924        }
7925        return sb.toString();
7926    }
7927
7928    private static String makeHex(byte[] bytes, int from, int len) {
7929        StringBuilder sb = new StringBuilder();
7930        for (int i = 0; i < len; i++) {
7931            sb.append(String.format("%02x", bytes[from+i]));
7932        }
7933        return sb.toString();
7934    }
7935
7936    private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
7937
7938        int len = array1.length + array2.length + array3.length;
7939
7940        if (array1.length != 0) {
7941            len++;                      /* add another byte for size */
7942        }
7943
7944        if (array2.length != 0) {
7945            len++;                      /* add another byte for size */
7946        }
7947
7948        if (array3.length != 0) {
7949            len++;                      /* add another byte for size */
7950        }
7951
7952        byte[] result = new byte[len];
7953
7954        int index = 0;
7955        if (array1.length != 0) {
7956            result[index] = (byte) (array1.length & 0xFF);
7957            index++;
7958            for (byte b : array1) {
7959                result[index] = b;
7960                index++;
7961            }
7962        }
7963
7964        if (array2.length != 0) {
7965            result[index] = (byte) (array2.length & 0xFF);
7966            index++;
7967            for (byte b : array2) {
7968                result[index] = b;
7969                index++;
7970            }
7971        }
7972
7973        if (array3.length != 0) {
7974            result[index] = (byte) (array3.length & 0xFF);
7975            index++;
7976            for (byte b : array3) {
7977                result[index] = b;
7978                index++;
7979            }
7980        }
7981        return result;
7982    }
7983
7984    private static byte[] concatHex(byte[] array1, byte[] array2) {
7985
7986        int len = array1.length + array2.length;
7987
7988        byte[] result = new byte[len];
7989
7990        int index = 0;
7991        if (array1.length != 0) {
7992            for (byte b : array1) {
7993                result[index] = b;
7994                index++;
7995            }
7996        }
7997
7998        if (array2.length != 0) {
7999            for (byte b : array2) {
8000                result[index] = b;
8001                index++;
8002            }
8003        }
8004
8005        return result;
8006    }
8007
8008    String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
8009        StringBuilder sb = new StringBuilder();
8010        for (String challenge : requestData) {
8011            if (challenge == null || challenge.isEmpty()) {
8012                continue;
8013            }
8014            logd("RAND = " + challenge);
8015
8016            byte[] rand = null;
8017            try {
8018                rand = parseHex(challenge);
8019            } catch (NumberFormatException e) {
8020                loge("malformed challenge");
8021                continue;
8022            }
8023
8024            String base64Challenge = android.util.Base64.encodeToString(
8025                    rand, android.util.Base64.NO_WRAP);
8026
8027            // Try USIM first for authentication.
8028            String tmResponse = tm.getIccAuthentication(tm.APPTYPE_USIM,
8029                    tm.AUTHTYPE_EAP_SIM, base64Challenge);
8030            if (tmResponse == null) {
8031                /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
8032                 */
8033                tmResponse = tm.getIccAuthentication(tm.APPTYPE_SIM,
8034                        tm.AUTHTYPE_EAP_SIM, base64Challenge);
8035            }
8036            logv("Raw Response - " + tmResponse);
8037
8038            if (tmResponse == null || tmResponse.length() <= 4) {
8039                loge("bad response - " + tmResponse);
8040                return null;
8041            }
8042
8043            byte[] result = android.util.Base64.decode(tmResponse, android.util.Base64.DEFAULT);
8044            logv("Hex Response -" + makeHex(result));
8045            int sres_len = result[0];
8046            if (sres_len >= result.length) {
8047                loge("malfomed response - " + tmResponse);
8048                return null;
8049            }
8050            String sres = makeHex(result, 1, sres_len);
8051            int kc_offset = 1 + sres_len;
8052            if (kc_offset >= result.length) {
8053                loge("malfomed response - " + tmResponse);
8054                return null;
8055            }
8056            int kc_len = result[kc_offset];
8057            if (kc_offset + kc_len > result.length) {
8058                loge("malfomed response - " + tmResponse);
8059                return null;
8060            }
8061            String kc = makeHex(result, 1 + kc_offset, kc_len);
8062            sb.append(":" + kc + ":" + sres);
8063            logv("kc:" + kc + " sres:" + sres);
8064        }
8065
8066        return sb.toString();
8067    }
8068
8069    void handleGsmAuthRequest(SimAuthRequestData requestData) {
8070        if (targetWificonfiguration == null
8071                || targetWificonfiguration.networkId == requestData.networkId) {
8072            logd("id matches targetWifiConfiguration");
8073        } else {
8074            logd("id does not match targetWifiConfiguration");
8075            return;
8076        }
8077
8078        TelephonyManager tm = (TelephonyManager)
8079                mContext.getSystemService(Context.TELEPHONY_SERVICE);
8080
8081        if (tm == null) {
8082            loge("could not get telephony manager");
8083            mWifiNative.simAuthFailedResponse(requestData.networkId);
8084            return;
8085        }
8086
8087        String response = getGsmSimAuthResponse(requestData.data, tm);
8088        if (response == null) {
8089            mWifiNative.simAuthFailedResponse(requestData.networkId);
8090        } else {
8091            logv("Supplicant Response -" + response);
8092            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
8093        }
8094    }
8095
8096    void handle3GAuthRequest(SimAuthRequestData requestData) {
8097        StringBuilder sb = new StringBuilder();
8098        byte[] rand = null;
8099        byte[] authn = null;
8100        String res_type = "UMTS-AUTH";
8101
8102        if (targetWificonfiguration == null
8103                || targetWificonfiguration.networkId == requestData.networkId) {
8104            logd("id matches targetWifiConfiguration");
8105        } else {
8106            logd("id does not match targetWifiConfiguration");
8107            return;
8108        }
8109        if (requestData.data.length == 2) {
8110            try {
8111                rand = parseHex(requestData.data[0]);
8112                authn = parseHex(requestData.data[1]);
8113            } catch (NumberFormatException e) {
8114                loge("malformed challenge");
8115            }
8116        } else {
8117               loge("malformed challenge");
8118        }
8119
8120        String tmResponse = "";
8121        if (rand != null && authn != null) {
8122            String base64Challenge = android.util.Base64.encodeToString(
8123                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
8124
8125            TelephonyManager tm = (TelephonyManager)
8126                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
8127            if (tm != null) {
8128                tmResponse = tm.getIccAuthentication(tm.APPTYPE_USIM,
8129                        tm.AUTHTYPE_EAP_AKA, base64Challenge);
8130                logv("Raw Response - " + tmResponse);
8131            } else {
8132                loge("could not get telephony manager");
8133            }
8134        }
8135
8136        boolean good_response = false;
8137        if (tmResponse != null && tmResponse.length() > 4) {
8138            byte[] result = android.util.Base64.decode(tmResponse,
8139                    android.util.Base64.DEFAULT);
8140            loge("Hex Response - " + makeHex(result));
8141            byte tag = result[0];
8142            if (tag == (byte) 0xdb) {
8143                logv("successful 3G authentication ");
8144                int res_len = result[1];
8145                String res = makeHex(result, 2, res_len);
8146                int ck_len = result[res_len + 2];
8147                String ck = makeHex(result, res_len + 3, ck_len);
8148                int ik_len = result[res_len + ck_len + 3];
8149                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
8150                sb.append(":" + ik + ":" + ck + ":" + res);
8151                logv("ik:" + ik + "ck:" + ck + " res:" + res);
8152                good_response = true;
8153            } else if (tag == (byte) 0xdc) {
8154                loge("synchronisation failure");
8155                int auts_len = result[1];
8156                String auts = makeHex(result, 2, auts_len);
8157                res_type = "UMTS-AUTS";
8158                sb.append(":" + auts);
8159                logv("auts:" + auts);
8160                good_response = true;
8161            } else {
8162                loge("bad response - unknown tag = " + tag);
8163            }
8164        } else {
8165            loge("bad response - " + tmResponse);
8166        }
8167
8168        if (good_response) {
8169            String response = sb.toString();
8170            logv("Supplicant Response -" + response);
8171            mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
8172        } else {
8173            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
8174        }
8175    }
8176
8177    /**
8178     * Automatically connect to the network specified
8179     *
8180     * @param networkId ID of the network to connect to
8181     * @param bssid BSSID of the network
8182     */
8183    public void autoConnectToNetwork(int networkId, String bssid) {
8184        sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);
8185    }
8186
8187    /**
8188     * Automatically roam to the network specified
8189     *
8190     * @param networkId ID of the network to roam to
8191     * @param scanResult scan result which identifies the network to roam to
8192     */
8193    public void autoRoamToNetwork(int networkId, ScanResult scanResult) {
8194        sendMessage(CMD_AUTO_ROAM, networkId, 0, scanResult);
8195    }
8196
8197    /**
8198     * Dynamically turn on/off WifiConnectivityManager
8199     *
8200     * @param enabled true-enable; false-disable
8201     */
8202    public void enableWifiConnectivityManager(boolean enabled) {
8203        sendMessage(CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER, enabled ? 1 : 0);
8204    }
8205
8206    /**
8207     * @param reason reason code from supplicant on network disconnected event
8208     * @return true if this is a suspicious disconnect
8209     */
8210    static boolean unexpectedDisconnectedReason(int reason) {
8211        return reason == 2              // PREV_AUTH_NOT_VALID
8212                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
8213                || reason == 7          // FRAME_FROM_NONASSOC_STA
8214                || reason == 8          // STA_HAS_LEFT
8215                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
8216                || reason == 14         // MICHAEL_MIC_FAILURE
8217                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
8218                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
8219                || reason == 18         // GROUP_CIPHER_NOT_VALID
8220                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
8221                || reason == 23         // IEEE_802_1X_AUTH_FAILED
8222                || reason == 34;        // DISASSOC_LOW_ACK
8223    }
8224
8225    /**
8226     * Update WifiMetrics before dumping
8227     */
8228    void updateWifiMetrics() {
8229        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworksSize();
8230        int numOpenNetworks = 0;
8231        int numPersonalNetworks = 0;
8232        int numEnterpriseNetworks = 0;
8233        int numNetworksAddedByUser = 0;
8234        int numNetworksAddedByApps = 0;
8235        for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) {
8236            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
8237                numOpenNetworks++;
8238            } else if (config.isEnterprise()) {
8239                numEnterpriseNetworks++;
8240            } else {
8241                numPersonalNetworks++;
8242            }
8243            if (config.selfAdded) {
8244                numNetworksAddedByUser++;
8245            } else {
8246                numNetworksAddedByApps++;
8247            }
8248        }
8249        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
8250        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
8251        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
8252        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
8253        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
8254        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
8255
8256        /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually
8257        mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt(
8258                mContext.getContentResolver(),
8259                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
8260                != Settings.Secure.LOCATION_MODE_OFF);
8261                */
8262
8263        /* <TODO> decide how statemachine will access WifiSettingsStore
8264        mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable());
8265         */
8266    }
8267
8268    private static String getLinkPropertiesSummary(LinkProperties lp) {
8269        List<String> attributes = new ArrayList(6);
8270        if (lp.hasIPv4Address()) {
8271            attributes.add("v4");
8272        }
8273        if (lp.hasIPv4DefaultRoute()) {
8274            attributes.add("v4r");
8275        }
8276        if (lp.hasIPv4DnsServer()) {
8277            attributes.add("v4dns");
8278        }
8279        if (lp.hasGlobalIPv6Address()) {
8280            attributes.add("v6");
8281        }
8282        if (lp.hasIPv6DefaultRoute()) {
8283            attributes.add("v6r");
8284        }
8285        if (lp.hasIPv6DnsServer()) {
8286            attributes.add("v6dns");
8287        }
8288
8289        return TextUtils.join(" ", attributes);
8290    }
8291
8292    private void wnmFrameReceived(WnmData event) {
8293        // %012x HS20-SUBSCRIPTION-REMEDIATION "%u %s", osu_method, url
8294        // %012x HS20-DEAUTH-IMMINENT-NOTICE "%u %u %s", code, reauth_delay, url
8295
8296        Intent intent = new Intent(WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION);
8297        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
8298
8299        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_BSSID, event.getBssid());
8300        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_URL, event.getUrl());
8301
8302        if (event.isDeauthEvent()) {
8303            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_ESS, event.isEss());
8304            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_DELAY, event.getDelay());
8305        } else {
8306            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_METHOD, event.getMethod());
8307            WifiConfiguration config = getCurrentWifiConfiguration();
8308            if (config != null && config.FQDN != null) {
8309                intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH,
8310                        mWifiConfigManager.matchProviderWithCurrentNetwork(config.FQDN));
8311            }
8312        }
8313        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
8314    }
8315}
8316