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