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