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