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