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