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