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