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