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