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