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