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