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