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