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