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