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