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