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