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