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