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