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