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