WifiStateMachine.java revision 843ee4e8b0b3332e6f7403fe3d8346cbb991f9b8
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            Set<Integer> removedNetworkIds;
5398            logStateAndMessage(message, this);
5399
5400            switch (message.what) {
5401                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5402                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
5403                    didBlackListBSSID = false;
5404                    bssid = (String) message.obj;
5405                    if (bssid == null || TextUtils.isEmpty(bssid)) {
5406                        // If BSSID is null, use the target roam BSSID
5407                        bssid = mTargetRoamBSSID;
5408                    }
5409                    if (bssid != null) {
5410                        // If we have a BSSID, tell configStore to black list it
5411                        if (mWifiConnectivityManager != null) {
5412                            didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid,
5413                                    false);
5414                        }
5415                    }
5416
5417                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
5418                            WifiConfiguration.NetworkSelectionStatus
5419                            .DISABLED_ASSOCIATION_REJECTION);
5420
5421                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
5422                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
5423                    reportConnectionAttemptEnd(
5424                            WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
5425                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5426                    mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(),
5427                            bssid,
5428                            WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
5429                    break;
5430                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5431                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
5432                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
5433                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5434                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
5435                                WifiConfiguration.NetworkSelectionStatus
5436                                        .DISABLED_AUTHENTICATION_FAILURE);
5437                    }
5438                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
5439                    reportConnectionAttemptEnd(
5440                            WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
5441                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5442                    mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(),
5443                            mTargetRoamBSSID,
5444                            WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
5445                    break;
5446                case WifiMonitor.SSID_TEMP_DISABLED:
5447                    Log.e(TAG, "Supplicant SSID temporary disabled:"
5448                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5449                    mWifiConfigManager.updateNetworkSelectionStatus(
5450                            message.arg1,
5451                            WifiConfiguration.NetworkSelectionStatus
5452                            .DISABLED_AUTHENTICATION_FAILURE);
5453                    reportConnectionAttemptEnd(
5454                            WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED,
5455                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5456                    mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(),
5457                            mTargetRoamBSSID,
5458                            WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
5459                    break;
5460                case WifiMonitor.SSID_REENABLED:
5461                    Log.d(TAG, "Supplicant SSID reenable:"
5462                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5463                    // Do not re-enable it in Quality Network Selection since framework has its own
5464                    // Algorithm of disable/enable
5465                    break;
5466                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5467                    SupplicantState state = handleSupplicantStateChange(message);
5468                    // A driver/firmware hang can now put the interface in a down state.
5469                    // We detect the interface going down and recover from it
5470                    if (!SupplicantState.isDriverActive(state)) {
5471                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5472                            handleNetworkDisconnect();
5473                        }
5474                        log("Detected an interface down, restart driver");
5475                        transitionTo(mDriverStoppedState);
5476                        sendMessage(CMD_START_DRIVER);
5477                        break;
5478                    }
5479
5480                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
5481                    // when authentication times out after a successful connection,
5482                    // we can figure this from the supplicant state. If supplicant
5483                    // state is DISCONNECTED, but the mNetworkInfo says we are not
5484                    // disconnected, we need to handle a disconnection
5485                    if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
5486                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5487                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
5488                        handleNetworkDisconnect();
5489                        transitionTo(mDisconnectedState);
5490                    }
5491
5492                    // If we have COMPLETED a connection to a BSSID, start doing
5493                    // DNAv4/DNAv6 -style probing for on-link neighbors of
5494                    // interest (e.g. routers); harmless if none are configured.
5495                    if (state == SupplicantState.COMPLETED) {
5496                        mIpManager.confirmConfiguration();
5497                    }
5498                    break;
5499                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5500                    if (message.arg1 == 1) {
5501                        mWifiNative.disconnect();
5502                        mTemporarilyDisconnectWifi = true;
5503                    } else {
5504                        mWifiNative.reconnect();
5505                        mTemporarilyDisconnectWifi = false;
5506                    }
5507                    break;
5508                case CMD_ADD_OR_UPDATE_NETWORK:
5509                    // Only the current foreground user can modify networks.
5510                    if (!mWifiConfigManager.isCurrentUserProfile(
5511                            UserHandle.getUserId(message.sendingUid))) {
5512                        loge("Only the current foreground user can modify networks "
5513                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5514                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5515                        replyToMessage(message, message.what, FAILURE);
5516                        break;
5517                    }
5518
5519                    config = (WifiConfiguration) message.obj;
5520
5521                    if (!recordUidIfAuthorized(config, message.sendingUid,
5522                            /* onlyAnnotate */ false)) {
5523                        logw("Not authorized to update network "
5524                             + " config=" + config.SSID
5525                             + " cnid=" + config.networkId
5526                             + " uid=" + message.sendingUid);
5527                        replyToMessage(message, message.what, FAILURE);
5528                        break;
5529                    }
5530
5531                    int res = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5532                    if (res < 0) {
5533                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5534                    } else {
5535                        WifiConfiguration curConfig = getCurrentWifiConfiguration();
5536                        if (curConfig != null && config != null) {
5537                            WifiConfiguration.NetworkSelectionStatus networkStatus =
5538                                    config.getNetworkSelectionStatus();
5539                            if (curConfig.priority < config.priority && networkStatus != null
5540                                    && !networkStatus.isNetworkPermanentlyDisabled()) {
5541                                // Interpret this as a connect attempt
5542                                // Set the last selected configuration so as to allow the system to
5543                                // stick the last user choice without persisting the choice
5544                                mWifiConfigManager.setAndEnableLastSelectedConfiguration(res);
5545                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
5546                                boolean persist = mWifiConfigManager
5547                                        .checkConfigOverridePermission(message.sendingUid);
5548                                if (mWifiConnectivityManager != null) {
5549                                    mWifiConnectivityManager.connectToUserSelectNetwork(res,
5550                                            persist);
5551                                }
5552
5553                                // Remember time of last connection attempt
5554                                lastConnectAttemptTimestamp = System.currentTimeMillis();
5555                                mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5556
5557                                // As a courtesy to the caller, trigger a scan now
5558                                startScan(ADD_OR_UPDATE_SOURCE, 0, null, WIFI_WORK_SOURCE);
5559                            }
5560                        }
5561                    }
5562                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
5563                    break;
5564                case CMD_REMOVE_NETWORK:
5565                    // Only the current foreground user can modify networks.
5566                    if (!mWifiConfigManager.isCurrentUserProfile(
5567                            UserHandle.getUserId(message.sendingUid))) {
5568                        loge("Only the current foreground user can modify networks "
5569                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5570                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5571                        replyToMessage(message, message.what, FAILURE);
5572                        break;
5573                    }
5574                    netId = message.arg1;
5575
5576                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
5577                            /* onlyAnnotate */ false)) {
5578                        logw("Not authorized to remove network "
5579                             + " cnid=" + netId
5580                             + " uid=" + message.sendingUid);
5581                        replyToMessage(message, message.what, FAILURE);
5582                        break;
5583                    }
5584
5585                    ok = mWifiConfigManager.removeNetwork(message.arg1);
5586                    if (!ok) {
5587                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5588                    }
5589                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5590                    break;
5591                case CMD_ENABLE_NETWORK:
5592                    // Only the current foreground user can modify networks.
5593                    if (!mWifiConfigManager.isCurrentUserProfile(
5594                            UserHandle.getUserId(message.sendingUid))) {
5595                        loge("Only the current foreground user can modify networks "
5596                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5597                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5598                        replyToMessage(message, message.what, FAILURE);
5599                        break;
5600                    }
5601
5602                    boolean disableOthers = message.arg2 == 1;
5603                    netId = message.arg1;
5604                    config = mWifiConfigManager.getWifiConfiguration(netId);
5605                    if (config == null) {
5606                        loge("No network with id = " + netId);
5607                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5608                        replyToMessage(message, message.what, FAILURE);
5609                        break;
5610                    }
5611                    // disable other only means select this network, does not mean all other
5612                    // networks need to be disabled
5613                    if (disableOthers) {
5614                        // Remember time of last connection attempt
5615                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5616                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5617                    }
5618                    // Cancel auto roam requests
5619                    autoRoamSetBSSID(netId, "any");
5620
5621                    ok = mWifiConfigManager.enableNetwork(
5622                            config, disableOthers, message.sendingUid);
5623                    if (!ok) {
5624                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5625                    } else {
5626                        if (disableOthers) {
5627                            mTargetNetworkId = netId;
5628                        }
5629                        mWifiConnectivityManager.forceConnectivityScan();
5630                    }
5631
5632                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5633                    break;
5634                case CMD_ENABLE_ALL_NETWORKS:
5635                    long time = android.os.SystemClock.elapsedRealtime();
5636                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
5637                        mWifiConfigManager.enableAllNetworks();
5638                        mLastEnableAllNetworksTime = time;
5639                    }
5640                    break;
5641                case WifiManager.DISABLE_NETWORK:
5642                    if (mWifiConfigManager.updateNetworkSelectionStatus(message.arg1,
5643                            WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) {
5644                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
5645                    } else {
5646                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5647                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5648                                WifiManager.ERROR);
5649                    }
5650                    break;
5651                case CMD_DISABLE_EPHEMERAL_NETWORK:
5652                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
5653                    if (config != null) {
5654                        if (config.networkId == mLastNetworkId) {
5655                            // Disconnect and let autojoin reselect a new network
5656                            sendMessage(CMD_DISCONNECT);
5657                        }
5658                    }
5659                    break;
5660                case CMD_BLACKLIST_NETWORK:
5661                    mWifiConfigManager.blackListBssid((String) message.obj);
5662                    break;
5663                case CMD_CLEAR_BLACKLIST:
5664                    mWifiConfigManager.clearBssidBlacklist();
5665                    break;
5666                case CMD_SAVE_CONFIG:
5667                    ok = mWifiConfigManager.saveConfig();
5668
5669                    if (DBG) logd("did save config " + ok);
5670                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
5671
5672                    // Inform the backup manager about a data change
5673                    mBackupManagerProxy.notifyDataChanged();
5674                    break;
5675                case CMD_GET_CONFIGURED_NETWORKS:
5676                    replyToMessage(message, message.what,
5677                            mWifiConfigManager.getSavedNetworks());
5678                    break;
5679                case WifiMonitor.SUP_REQUEST_IDENTITY:
5680                    int networkId = message.arg2;
5681                    boolean identitySent = false;
5682                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
5683
5684                    if (targetWificonfiguration != null
5685                            && targetWificonfiguration.enterpriseConfig != null) {
5686                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
5687                    }
5688
5689                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
5690                    if (targetWificonfiguration != null
5691                            && targetWificonfiguration.networkId == networkId
5692                            && (targetWificonfiguration.allowedKeyManagement
5693                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X)
5694                                || targetWificonfiguration.allowedKeyManagement
5695                                    .get(WifiConfiguration.KeyMgmt.WPA_EAP))
5696                            && TelephonyUtil.isSimEapMethod(eapMethod)) {
5697                        String identity = TelephonyUtil.getSimIdentity(mContext, eapMethod);
5698                        if (identity != null) {
5699                            mWifiNative.simIdentityResponse(networkId, identity);
5700                            identitySent = true;
5701                        }
5702                    }
5703                    if (!identitySent) {
5704                        // Supplicant lacks credentials to connect to that network, hence black list
5705                        ssid = (String) message.obj;
5706                        if (targetWificonfiguration != null && ssid != null
5707                                && targetWificonfiguration.SSID != null
5708                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
5709                            mWifiConfigManager.updateNetworkSelectionStatus(targetWificonfiguration,
5710                                    WifiConfiguration.NetworkSelectionStatus
5711                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
5712                        }
5713                        // Disconnect now, as we don't have any way to fullfill
5714                        // the  supplicant request.
5715                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
5716                                WifiConfiguration.INVALID_NETWORK_ID);
5717                        mWifiNative.disconnect();
5718                    }
5719                    break;
5720                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5721                    logd("Received SUP_REQUEST_SIM_AUTH");
5722                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5723                    if (requestData != null) {
5724                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5725                            handleGsmAuthRequest(requestData);
5726                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5727                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5728                            handle3GAuthRequest(requestData);
5729                        }
5730                    } else {
5731                        loge("Invalid sim auth request");
5732                    }
5733                    break;
5734                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5735                    replyToMessage(message, message.what,
5736                            mWifiConfigManager.getPrivilegedSavedNetworks());
5737                    break;
5738                case CMD_GET_MATCHING_CONFIG:
5739                    replyToMessage(message, message.what,
5740                            mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
5741                    break;
5742                case CMD_RECONNECT:
5743                    if (mWifiConnectivityManager != null) {
5744                        mWifiConnectivityManager.forceConnectivityScan();
5745                    }
5746                    break;
5747                case CMD_REASSOCIATE:
5748                    lastConnectAttemptTimestamp = System.currentTimeMillis();
5749                    mWifiNative.reassociate();
5750                    break;
5751                case CMD_RELOAD_TLS_AND_RECONNECT:
5752                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
5753                        logd("Reconnecting to give a chance to un-connected TLS networks");
5754                        mWifiNative.disconnect();
5755                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5756                        mWifiNative.reconnect();
5757                    }
5758                    break;
5759                case CMD_AUTO_ROAM:
5760                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5761                    return HANDLED;
5762                case CMD_AUTO_CONNECT:
5763                    /* Work Around: wpa_supplicant can get in a bad state where it returns a non
5764                     * associated status to the STATUS command but somehow-someplace still thinks
5765                     * it is associated and thus will ignore select/reconnect command with
5766                     * following message:
5767                     * "Already associated with the selected network - do nothing"
5768                     *
5769                     * Hence, sends a disconnect to supplicant first.
5770                     */
5771                    didDisconnect = false;
5772                    if (getCurrentState() != mDisconnectedState) {
5773                        /** Supplicant will ignore the reconnect if we are currently associated,
5774                         * hence trigger a disconnect
5775                         */
5776                        didDisconnect = true;
5777                        mWifiNative.disconnect();
5778                    }
5779
5780                    /* connect command coming from auto-join */
5781                    netId = message.arg1;
5782                    mTargetNetworkId = netId;
5783                    mTargetRoamBSSID = (String) message.obj;
5784                    config = mWifiConfigManager.getWifiConfiguration(netId);
5785                    logd("CMD_AUTO_CONNECT sup state "
5786                            + mSupplicantStateTracker.getSupplicantStateName()
5787                            + " my state " + getCurrentState().getName()
5788                            + " nid=" + Integer.toString(netId)
5789                            + " roam=" + Boolean.toString(mAutoRoaming));
5790                    if (config == null) {
5791                        loge("AUTO_CONNECT and no config, bail out...");
5792                        break;
5793                    }
5794
5795                    /* Make sure we cancel any previous roam request */
5796                    setTargetBssid(config, mTargetRoamBSSID);
5797
5798                    /* Save the network config */
5799                    logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
5800                            + " nid=" + Integer.toString(netId));
5801                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
5802                    netId = result.getNetworkId();
5803                    logd("CMD_AUTO_CONNECT did save config -> "
5804                            + " nid=" + Integer.toString(netId));
5805
5806                    // Since we updated the config,read it back from config store:
5807                    config = mWifiConfigManager.getWifiConfiguration(netId);
5808                    if (config == null) {
5809                        loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
5810                        break;
5811                    }
5812                    if (netId != config.networkId) {
5813                        loge("CMD_AUTO_CONNECT couldn't update the config, want"
5814                                + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
5815                        break;
5816                    }
5817
5818                    if (deferForUserInput(message, netId, false)) {
5819                        break;
5820                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5821                                                                   WifiConfiguration.USER_BANNED) {
5822                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5823                                WifiManager.NOT_AUTHORIZED);
5824                        break;
5825                    }
5826
5827                    // If we're autojoining a network that the user or an app explicitly selected,
5828                    // keep track of the UID that selected it.
5829                    // TODO(b/26786318): Keep track of the lastSelectedConfiguration and the
5830                    // lastConnectUid on a per-user basis.
5831                    int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
5832
5833                    //Start a new ConnectionEvent due to auto_connect, assume we are connecting
5834                    //between different networks due to QNS, setting ROAM_UNRELATED
5835                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5836                            WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
5837                    if (!didDisconnect) {
5838                        //If we were originally disconnected, then this was not any kind of ROAM
5839                        mWifiMetrics.setConnectionEventRoamType(
5840                                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
5841                    }
5842                    //Determine if this CONNECTION is for a user selection
5843                    if (mWifiConfigManager.isLastSelectedConfiguration(config)
5844                            && mWifiConfigManager.isCurrentUserProfile(
5845                                UserHandle.getUserId(config.lastConnectUid))) {
5846                        lastConnectUid = config.lastConnectUid;
5847                        mWifiMetrics.setConnectionEventRoamType(
5848                                WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
5849                    }
5850                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
5851                            lastConnectUid) && mWifiNative.reconnect()) {
5852                        lastConnectAttemptTimestamp = System.currentTimeMillis();
5853                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
5854                        config = mWifiConfigManager.getWifiConfiguration(netId);
5855                        if (config != null
5856                                && !mWifiConfigManager.isLastSelectedConfiguration(config)) {
5857                            // If we autojoined a different config than the user selected one,
5858                            // it means we could not see the last user selection,
5859                            // or that the last user selection was faulty and ended up blacklisted
5860                            // for some reason (in which case the user is notified with an error
5861                            // message in the Wifi picker), and thus we managed to auto-join away
5862                            // from the selected  config. -> in that case we need to forget
5863                            // the selection because we don't want to abruptly switch back to it.
5864                            //
5865                            // Note that the user selection is also forgotten after a period of time
5866                            // during which the device has been disconnected.
5867                            // The default value is 30 minutes : see the code path at bottom of
5868                            // setScanResults() function.
5869                            mWifiConfigManager.
5870                                 setAndEnableLastSelectedConfiguration(
5871                                         WifiConfiguration.INVALID_NETWORK_ID);
5872                        }
5873                        mAutoRoaming = false;
5874                        if (isRoaming() || linkDebouncing) {
5875                            transitionTo(mRoamingState);
5876                        } else if (didDisconnect) {
5877                            transitionTo(mDisconnectingState);
5878                        }
5879                    } else {
5880                        loge("Failed to connect config: " + config + " netId: " + netId);
5881                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5882                                WifiManager.ERROR);
5883                        reportConnectionAttemptEnd(
5884                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5885                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5886                        break;
5887                    }
5888                    break;
5889                case CMD_REMOVE_APP_CONFIGURATIONS:
5890                    removedNetworkIds =
5891                            mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
5892                    if (removedNetworkIds.contains(mTargetNetworkId) ||
5893                            removedNetworkIds.contains(mLastNetworkId)) {
5894                        // Disconnect and let autojoin reselect a new network.
5895                        sendMessage(CMD_DISCONNECT);
5896                    }
5897                    break;
5898                case CMD_REMOVE_USER_CONFIGURATIONS:
5899                    removedNetworkIds =
5900                            mWifiConfigManager.removeNetworksForUser((Integer) message.arg1);
5901                    if (removedNetworkIds.contains(mTargetNetworkId) ||
5902                            removedNetworkIds.contains(mLastNetworkId)) {
5903                        // Disconnect and let autojoin reselect a new network.
5904                        sendMessage(CMD_DISCONNECT);
5905                    }
5906                    break;
5907                case WifiManager.CONNECT_NETWORK:
5908                    // Only the current foreground user and System UI (which runs as user 0 but acts
5909                    // on behalf of the current foreground user) can modify networks.
5910                    if (!mWifiConfigManager.isCurrentUserProfile(
5911                            UserHandle.getUserId(message.sendingUid)) &&
5912                            message.sendingUid != mSystemUiUid) {
5913                        loge("Only the current foreground user can modify networks "
5914                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5915                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5916                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5917                                       WifiManager.NOT_AUTHORIZED);
5918                        break;
5919                    }
5920
5921                    /**
5922                     *  The connect message can contain a network id passed as arg1 on message or
5923                     * or a config passed as obj on message.
5924                     * For a new network, a config is passed to create and connect.
5925                     * For an existing network, a network id is passed
5926                     */
5927                    netId = message.arg1;
5928                    config = (WifiConfiguration) message.obj;
5929                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5930                    boolean updatedExisting = false;
5931
5932                    /* Save the network config */
5933                    if (config != null) {
5934                        // When connecting to an access point, WifiStateMachine wants to update the
5935                        // relevant config with administrative data. This update should not be
5936                        // considered a 'real' update, therefore lockdown by Device Owner must be
5937                        // disregarded.
5938                        if (!recordUidIfAuthorized(config, message.sendingUid,
5939                                /* onlyAnnotate */ true)) {
5940                            logw("Not authorized to update network "
5941                                 + " config=" + config.SSID
5942                                 + " cnid=" + config.networkId
5943                                 + " uid=" + message.sendingUid);
5944                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5945                                           WifiManager.NOT_AUTHORIZED);
5946                            break;
5947                        }
5948                        String configKey = config.configKey(true /* allowCached */);
5949                        WifiConfiguration savedConfig =
5950                                mWifiConfigManager.getWifiConfiguration(configKey);
5951                        if (savedConfig != null) {
5952                            // There is an existing config with this netId, but it wasn't exposed
5953                            // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigManager#
5954                            // getConfiguredNetworks). Remove those bits and update the config.
5955                            config = savedConfig;
5956                            logd("CONNECT_NETWORK updating existing config with id=" +
5957                                    config.networkId + " configKey=" + configKey);
5958                            config.ephemeral = false;
5959                            mWifiConfigManager.updateNetworkSelectionStatus(config,
5960                                    WifiConfiguration.NetworkSelectionStatus
5961                                    .NETWORK_SELECTION_ENABLE);
5962                            updatedExisting = true;
5963                        }
5964
5965                        result = mWifiConfigManager.saveNetwork(config, message.sendingUid);
5966                        netId = result.getNetworkId();
5967                    }
5968                    config = mWifiConfigManager.getWifiConfiguration(netId);
5969                    if (config == null) {
5970                        logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
5971                                + mSupplicantStateTracker.getSupplicantStateName() + " my state "
5972                                + getCurrentState().getName());
5973                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5974                                WifiManager.ERROR);
5975                        break;
5976                    }
5977                    mTargetNetworkId = netId;
5978                    autoRoamSetBSSID(netId, "any");
5979                    if (message.sendingUid == Process.WIFI_UID
5980                        || message.sendingUid == Process.SYSTEM_UID) {
5981                        // As a sanity measure, clear the BSSID in the supplicant network block.
5982                        // If system or Wifi Settings want to connect, they will not
5983                        // specify the BSSID.
5984                        // If an app however had added a BSSID to this configuration, and the BSSID
5985                        // was wrong, Then we would forever fail to connect until that BSSID
5986                        // is cleaned up.
5987                        clearConfigBSSID(config, "CONNECT_NETWORK");
5988                    }
5989
5990                    if (deferForUserInput(message, netId, true)) {
5991                        break;
5992                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5993                                                                    WifiConfiguration.USER_BANNED) {
5994                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5995                                WifiManager.NOT_AUTHORIZED);
5996                        break;
5997                    }
5998
5999                    mAutoRoaming = false;
6000
6001                    /* Tell network selection the user did try to connect to that network if from
6002                    settings */
6003                    boolean persist =
6004                        mWifiConfigManager.checkConfigOverridePermission(message.sendingUid);
6005
6006
6007                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(netId);
6008                    if (mWifiConnectivityManager != null) {
6009                        mWifiConnectivityManager.connectToUserSelectNetwork(netId, persist);
6010                    }
6011                    didDisconnect = false;
6012                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
6013                            && mLastNetworkId != netId) {
6014                        /** Supplicant will ignore the reconnect if we are currently associated,
6015                         * hence trigger a disconnect
6016                         */
6017                        didDisconnect = true;
6018                        mWifiNative.disconnect();
6019                    }
6020
6021                    //Start a new ConnectionEvent due to connect_network, this is always user
6022                    //selected
6023                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
6024                            WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
6025                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ true,
6026                            message.sendingUid) && mWifiNative.reconnect()) {
6027                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6028                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
6029
6030                        /* The state tracker handles enabling networks upon completion/failure */
6031                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
6032                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
6033                        if (didDisconnect) {
6034                            /* Expect a disconnection from the old connection */
6035                            transitionTo(mDisconnectingState);
6036                        } else if (updatedExisting && getCurrentState() == mConnectedState &&
6037                                getCurrentWifiConfiguration().networkId == netId) {
6038                            // Update the current set of network capabilities, but stay in the
6039                            // current state.
6040                            updateCapabilities(config);
6041                        } else {
6042                            /**
6043                             * Directly go to disconnected state where we
6044                             * process the connection events from supplicant
6045                             */
6046                            transitionTo(mDisconnectedState);
6047                        }
6048                    } else {
6049                        loge("Failed to connect config: " + config + " netId: " + netId);
6050                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6051                                WifiManager.ERROR);
6052                        reportConnectionAttemptEnd(
6053                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6054                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6055                        break;
6056                    }
6057                    break;
6058                case WifiManager.SAVE_NETWORK:
6059                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6060                    // Fall thru
6061                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
6062                    // Only the current foreground user can modify networks.
6063                    if (!mWifiConfigManager.isCurrentUserProfile(
6064                            UserHandle.getUserId(message.sendingUid))) {
6065                        loge("Only the current foreground user can modify networks "
6066                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
6067                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6068                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6069                                WifiManager.NOT_AUTHORIZED);
6070                        break;
6071                    }
6072
6073                    lastSavedConfigurationAttempt = null; // Used for debug
6074                    config = (WifiConfiguration) message.obj;
6075                    if (config == null) {
6076                        loge("ERROR: SAVE_NETWORK with null configuration"
6077                                + mSupplicantStateTracker.getSupplicantStateName()
6078                                + " my state " + getCurrentState().getName());
6079                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6080                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6081                                WifiManager.ERROR);
6082                        break;
6083                    }
6084                    lastSavedConfigurationAttempt = new WifiConfiguration(config);
6085                    int nid = config.networkId;
6086                    logd("SAVE_NETWORK id=" + Integer.toString(nid)
6087                                + " config=" + config.SSID
6088                                + " nid=" + config.networkId
6089                                + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
6090                                + " my state " + getCurrentState().getName());
6091
6092                    // Only record the uid if this is user initiated
6093                    boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
6094                    if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
6095                            /* onlyAnnotate */ false)) {
6096                        logw("Not authorized to update network "
6097                             + " config=" + config.SSID
6098                             + " cnid=" + config.networkId
6099                             + " uid=" + message.sendingUid);
6100                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6101                                       WifiManager.NOT_AUTHORIZED);
6102                        break;
6103                    }
6104
6105                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
6106                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
6107                        if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
6108                            if (result.hasIpChanged()) {
6109                                // The currently connection configuration was changed
6110                                // We switched from DHCP to static or from static to DHCP, or the
6111                                // static IP address has changed.
6112                                log("Reconfiguring IP on connection");
6113                                // TODO: clear addresses and disable IPv6
6114                                // to simplify obtainingIpState.
6115                                transitionTo(mObtainingIpState);
6116                            }
6117                            if (result.hasProxyChanged()) {
6118                                log("Reconfiguring proxy on connection");
6119                                mIpManager.setHttpProxy(
6120                                        mWifiConfigManager.getProxyProperties(mLastNetworkId));
6121                            }
6122                        }
6123                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
6124                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6125
6126                        if (DBG) {
6127                           logd("Success save network nid="
6128                                    + Integer.toString(result.getNetworkId()));
6129                        }
6130
6131                        /**
6132                         * If the command comes from WifiManager, then
6133                         * tell autojoin the user did try to modify and save that network,
6134                         * and interpret the SAVE_NETWORK as a request to connect
6135                         */
6136                        boolean user = message.what == WifiManager.SAVE_NETWORK;
6137
6138                        // Did this connect come from settings
6139                        boolean persistConnect =
6140                                mWifiConfigManager.checkConfigOverridePermission(
6141                                        message.sendingUid);
6142
6143                        if (user) {
6144                            mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
6145                            mWifiConfigManager.writeKnownNetworkHistory();
6146                        }
6147
6148                        if (mWifiConnectivityManager != null) {
6149                            mWifiConnectivityManager.connectToUserSelectNetwork(
6150                                    result.getNetworkId(), persistConnect);
6151                        }
6152                    } else {
6153                        loge("Failed to save network");
6154                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6155                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6156                                WifiManager.ERROR);
6157                    }
6158                    break;
6159                case WifiManager.FORGET_NETWORK:
6160                    // Only the current foreground user can modify networks.
6161                    if (!mWifiConfigManager.isCurrentUserProfile(
6162                            UserHandle.getUserId(message.sendingUid))) {
6163                        loge("Only the current foreground user can modify networks "
6164                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
6165                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6166                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6167                                WifiManager.NOT_AUTHORIZED);
6168                        break;
6169                    }
6170
6171                    // Debug only, remember last configuration that was forgotten
6172                    WifiConfiguration toRemove
6173                            = mWifiConfigManager.getWifiConfiguration(message.arg1);
6174                    if (toRemove == null) {
6175                        lastForgetConfigurationAttempt = null;
6176                    } else {
6177                        lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
6178                    }
6179                    // check that the caller owns this network
6180                    netId = message.arg1;
6181
6182                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
6183                            /* onlyAnnotate */ false)) {
6184                        logw("Not authorized to forget network "
6185                             + " cnid=" + netId
6186                             + " uid=" + message.sendingUid);
6187                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6188                                WifiManager.NOT_AUTHORIZED);
6189                        break;
6190                    }
6191
6192                    if (mWifiConfigManager.forgetNetwork(message.arg1)) {
6193                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
6194                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
6195                                (WifiConfiguration) message.obj);
6196                    } else {
6197                        loge("Failed to forget network");
6198                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
6199                                WifiManager.ERROR);
6200                    }
6201                    break;
6202                case WifiManager.START_WPS:
6203                    WpsInfo wpsInfo = (WpsInfo) message.obj;
6204                    WpsResult wpsResult;
6205                    switch (wpsInfo.setup) {
6206                        case WpsInfo.PBC:
6207                            wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
6208                            break;
6209                        case WpsInfo.KEYPAD:
6210                            wpsResult = mWifiConfigManager.startWpsWithPinFromAccessPoint(wpsInfo);
6211                            break;
6212                        case WpsInfo.DISPLAY:
6213                            wpsResult = mWifiConfigManager.startWpsWithPinFromDevice(wpsInfo);
6214                            break;
6215                        default:
6216                            wpsResult = new WpsResult(Status.FAILURE);
6217                            loge("Invalid setup for WPS");
6218                            break;
6219                    }
6220                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
6221                            (WifiConfiguration.INVALID_NETWORK_ID);
6222                    if (wpsResult.status == Status.SUCCESS) {
6223                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
6224                        transitionTo(mWpsRunningState);
6225                    } else {
6226                        loge("Failed to start WPS with config " + wpsInfo.toString());
6227                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
6228                    }
6229                    break;
6230                case CMD_ASSOCIATED_BSSID:
6231                    // This is where we can confirm the connection BSSID. Use it to find the
6232                    // right ScanDetail to populate metrics.
6233                    String someBssid = (String) message.obj;
6234                    if (someBssid != null) {
6235                        //Get the config associated with this connection attempt
6236                        WifiConfiguration someConf =
6237                                mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
6238                        // Get the ScanDetail associated with this BSSID
6239                        ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCache(
6240                                someConf);
6241                        if (scanDetailCache != null) {
6242                            mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
6243                                    someBssid));
6244                        }
6245                    }
6246                    return NOT_HANDLED;
6247                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6248                    if (DBG) log("Network connection established");
6249                    mLastNetworkId = message.arg1;
6250                    mLastBssid = (String) message.obj;
6251
6252                    mWifiInfo.setBSSID(mLastBssid);
6253                    mWifiInfo.setNetworkId(mLastNetworkId);
6254                    mWifiQualifiedNetworkSelector
6255                            .enableBssidForQualityNetworkSelection(mLastBssid, true);
6256                    sendNetworkStateChangeBroadcast(mLastBssid);
6257                    transitionTo(mObtainingIpState);
6258                    break;
6259                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6260                    // Calling handleNetworkDisconnect here is redundant because we might already
6261                    // have called it when leaving L2ConnectedState to go to disconnecting state
6262                    // or thru other path
6263                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
6264                    // if they are valid, and only in this case call handleNEtworkDisconnect,
6265                    // TODO: this should be fixed for a L MR release
6266                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
6267                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
6268                    // at the chip etc...
6269                    if (DBG) log("ConnectModeState: Network connection lost ");
6270                    handleNetworkDisconnect();
6271                    transitionTo(mDisconnectedState);
6272                    break;
6273                case CMD_ADD_PASSPOINT_MO:
6274                    res = mWifiConfigManager.addPasspointManagementObject((String) message.obj);
6275                    replyToMessage(message, message.what, res);
6276                    break;
6277                case CMD_MODIFY_PASSPOINT_MO:
6278                    if (message.obj != null) {
6279                        Bundle bundle = (Bundle) message.obj;
6280                        ArrayList<PasspointManagementObjectDefinition> mos =
6281                                bundle.getParcelableArrayList("MOS");
6282                        res = mWifiConfigManager.modifyPasspointMo(bundle.getString("FQDN"), mos);
6283                    } else {
6284                        res = 0;
6285                    }
6286                    replyToMessage(message, message.what, res);
6287
6288                    break;
6289                case CMD_QUERY_OSU_ICON:
6290                    if (mWifiConfigManager.queryPasspointIcon(
6291                            ((Bundle) message.obj).getLong("BSSID"),
6292                            ((Bundle) message.obj).getString("FILENAME"))) {
6293                        res = 1;
6294                    } else {
6295                        res = 0;
6296                    }
6297                    replyToMessage(message, message.what, res);
6298                    break;
6299                case CMD_MATCH_PROVIDER_NETWORK:
6300                    res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
6301                    replyToMessage(message, message.what, res);
6302                    break;
6303                default:
6304                    return NOT_HANDLED;
6305            }
6306            return HANDLED;
6307        }
6308    }
6309
6310    private void updateCapabilities(WifiConfiguration config) {
6311        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
6312        if (config != null) {
6313            if (config.ephemeral) {
6314                networkCapabilities.removeCapability(
6315                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
6316            } else {
6317                networkCapabilities.addCapability(
6318                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
6319            }
6320
6321            networkCapabilities.setSignalStrength(
6322                    (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI)
6323                    ? mWifiInfo.getRssi()
6324                    : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
6325        }
6326
6327        if (mWifiInfo.getMeteredHint()) {
6328            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
6329        }
6330
6331        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
6332    }
6333
6334    private class WifiNetworkAgent extends NetworkAgent {
6335        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
6336                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
6337            super(l, c, TAG, ni, nc, lp, score, misc);
6338        }
6339        protected void unwanted() {
6340            // Ignore if we're not the current networkAgent.
6341            if (this != mNetworkAgent) return;
6342            if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
6343                    + Integer.toString(mWifiInfo.score));
6344            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
6345        }
6346
6347        @Override
6348        protected void networkStatus(int status, String redirectUrl) {
6349            if (this != mNetworkAgent) return;
6350            if (status == NetworkAgent.INVALID_NETWORK) {
6351                if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
6352                        + Integer.toString(mWifiInfo.score));
6353                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
6354            } else if (status == NetworkAgent.VALID_NETWORK) {
6355                if (DBG) {
6356                    log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
6357                            + Integer.toString(mWifiInfo.score));
6358                }
6359                doNetworkStatus(status);
6360            }
6361        }
6362
6363        @Override
6364        protected void saveAcceptUnvalidated(boolean accept) {
6365            if (this != mNetworkAgent) return;
6366            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
6367        }
6368
6369        @Override
6370        protected void startPacketKeepalive(Message msg) {
6371            WifiStateMachine.this.sendMessage(
6372                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
6373        }
6374
6375        @Override
6376        protected void stopPacketKeepalive(Message msg) {
6377            WifiStateMachine.this.sendMessage(
6378                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
6379        }
6380
6381        @Override
6382        protected void setSignalStrengthThresholds(int[] thresholds) {
6383            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
6384            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
6385            //    MAX_VALUE at the start/end of the thresholds array if necessary.
6386            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
6387            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
6388            //    re-arm the hardware event. This needs to be done on the state machine thread to
6389            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
6390            //    sent in the NetworkCapabilities) must be the one received from the hardware event
6391            //    received, or we might skip callbacks.
6392            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
6393            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
6394            if (thresholds.length == 0) {
6395                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
6396                        mWifiInfo.getRssi());
6397                return;
6398            }
6399            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
6400            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
6401            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
6402            Arrays.sort(rssiVals);
6403            byte[] rssiRange = new byte[rssiVals.length];
6404            for (int i = 0; i < rssiVals.length; i++) {
6405                int val = rssiVals[i];
6406                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
6407                    rssiRange[i] = (byte) val;
6408                } else {
6409                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
6410                            + Arrays.toString(rssiVals));
6411                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
6412                            mWifiInfo.getRssi());
6413                    return;
6414                }
6415            }
6416            // TODO: Do we quash rssi values in this sorted array which are very close?
6417            mRssiRanges = rssiRange;
6418            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
6419                    mWifiInfo.getRssi());
6420        }
6421
6422        @Override
6423        protected void preventAutomaticReconnect() {
6424            if (this != mNetworkAgent) return;
6425            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
6426        }
6427    }
6428
6429    void unwantedNetwork(int reason) {
6430        sendMessage(CMD_UNWANTED_NETWORK, reason);
6431    }
6432
6433    void doNetworkStatus(int status) {
6434        sendMessage(CMD_NETWORK_STATUS, status);
6435    }
6436
6437    // rfc4186 & rfc4187:
6438    // create Permanent Identity base on IMSI,
6439    // identity = usernam@realm
6440    // with username = prefix | IMSI
6441    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
6442    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
6443        String mcc;
6444        String mnc;
6445        String prefix;
6446
6447        if (imsi == null || imsi.isEmpty())
6448            return "";
6449
6450        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
6451            prefix = "1";
6452        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
6453            prefix = "0";
6454        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
6455            prefix = "6";
6456        else  // not a valide EapMethod
6457            return "";
6458
6459        /* extract mcc & mnc from mccMnc */
6460        if (mccMnc != null && !mccMnc.isEmpty()) {
6461            mcc = mccMnc.substring(0, 3);
6462            mnc = mccMnc.substring(3);
6463            if (mnc.length() == 2)
6464                mnc = "0" + mnc;
6465        } else {
6466            // extract mcc & mnc from IMSI, assume mnc size is 3
6467            mcc = imsi.substring(0, 3);
6468            mnc = imsi.substring(3, 6);
6469        }
6470
6471        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
6472    }
6473
6474    boolean startScanForConfiguration(WifiConfiguration config) {
6475        if (config == null)
6476            return false;
6477
6478        // We are still seeing a fairly high power consumption triggered by autojoin scans
6479        // Hence do partial scans only for PSK configuration that are roamable since the
6480        // primary purpose of the partial scans is roaming.
6481        // Full badn scans with exponential backoff for the purpose or extended roaming and
6482        // network switching are performed unconditionally.
6483        ScanDetailCache scanDetailCache =
6484                mWifiConfigManager.getScanDetailCache(config);
6485        if (scanDetailCache == null
6486                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
6487                || scanDetailCache.size() > 6) {
6488            //return true but to not trigger the scan
6489            return true;
6490        }
6491        HashSet<Integer> freqs = mWifiConfigManager.makeChannelList(config, ONE_HOUR_MILLI);
6492        if (freqs != null && freqs.size() != 0) {
6493            //if (DBG) {
6494            logd("starting scan for " + config.configKey() + " with " + freqs);
6495            //}
6496            Set<Integer> hiddenNetworkIds = new HashSet<>();
6497            if (config.hiddenSSID) {
6498                hiddenNetworkIds.add(config.networkId);
6499            }
6500            // Call wifi native to start the scan
6501            if (startScanNative(freqs, hiddenNetworkIds, WIFI_WORK_SOURCE)) {
6502                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
6503            } else {
6504                // used for debug only, mark scan as failed
6505                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
6506            }
6507            return true;
6508        } else {
6509            if (DBG) logd("no channels for " + config.configKey());
6510            return false;
6511        }
6512    }
6513
6514    void clearCurrentConfigBSSID(String dbg) {
6515        // Clear the bssid in the current config's network block
6516        WifiConfiguration config = getCurrentWifiConfiguration();
6517        if (config == null)
6518            return;
6519        clearConfigBSSID(config, dbg);
6520    }
6521    void clearConfigBSSID(WifiConfiguration config, String dbg) {
6522        if (config == null)
6523            return;
6524        if (DBG) {
6525            logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
6526                    + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
6527                    + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
6528        }
6529        if (DBG) {
6530           logd(dbg + " " + config.SSID
6531                    + " nid=" + Integer.toString(config.networkId));
6532        }
6533        mWifiConfigManager.saveWifiConfigBSSID(config, "any");
6534    }
6535
6536    class L2ConnectedState extends State {
6537        @Override
6538        public void enter() {
6539            mRssiPollToken++;
6540            if (mEnableRssiPolling) {
6541                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
6542            }
6543            if (mNetworkAgent != null) {
6544                loge("Have NetworkAgent when entering L2Connected");
6545                setNetworkDetailedState(DetailedState.DISCONNECTED);
6546            }
6547            setNetworkDetailedState(DetailedState.CONNECTING);
6548
6549            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
6550                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
6551                    mLinkProperties, 60, mNetworkMisc);
6552
6553            // We must clear the config BSSID, as the wifi chipset may decide to roam
6554            // from this point on and having the BSSID specified in the network block would
6555            // cause the roam to faile and the device to disconnect
6556            clearCurrentConfigBSSID("L2ConnectedState");
6557            mCountryCode.setReadyForChange(false);
6558            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
6559        }
6560
6561        @Override
6562        public void exit() {
6563            mIpManager.stop();
6564
6565            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
6566            // Bug: 15347363
6567            // For paranoia's sake, call handleNetworkDisconnect
6568            // only if BSSID is null or last networkId
6569            // is not invalid.
6570            if (DBG) {
6571                StringBuilder sb = new StringBuilder();
6572                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
6573                if (mLastBssid !=null) {
6574                    sb.append(" ").append(mLastBssid);
6575                }
6576            }
6577            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6578                handleNetworkDisconnect();
6579            }
6580            mCountryCode.setReadyForChange(true);
6581            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
6582        }
6583
6584        @Override
6585        public boolean processMessage(Message message) {
6586            logStateAndMessage(message, this);
6587
6588            switch (message.what) {
6589                case DhcpClient.CMD_PRE_DHCP_ACTION:
6590                    handlePreDhcpSetup();
6591                    break;
6592                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
6593                    mIpManager.completedPreDhcpAction();
6594                    break;
6595                case DhcpClient.CMD_POST_DHCP_ACTION:
6596                    handlePostDhcpSetup();
6597                    // We advance to mConnectedState because IpManager will also send a
6598                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
6599                    // which calls updateLinkProperties, which then sends
6600                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
6601                    //
6602                    // In the event of failure, we transition to mDisconnectingState
6603                    // similarly--via messages sent back from IpManager.
6604                    break;
6605                case CMD_IPV4_PROVISIONING_SUCCESS: {
6606                    handleIPv4Success((DhcpResults) message.obj);
6607                    sendNetworkStateChangeBroadcast(mLastBssid);
6608                    break;
6609                }
6610                case CMD_IPV4_PROVISIONING_FAILURE: {
6611                    handleIPv4Failure();
6612                    break;
6613                }
6614                case CMD_IP_CONFIGURATION_SUCCESSFUL:
6615                    handleSuccessfulIpConfiguration();
6616                    reportConnectionAttemptEnd(
6617                            WifiMetrics.ConnectionEvent.FAILURE_NONE,
6618                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6619                    sendConnectedState();
6620                    transitionTo(mConnectedState);
6621                    break;
6622                case CMD_IP_CONFIGURATION_LOST:
6623                    // Get Link layer stats so that we get fresh tx packet counters.
6624                    getWifiLinkLayerStats(true);
6625                    handleIpConfigurationLost();
6626                    transitionTo(mDisconnectingState);
6627                    break;
6628                case CMD_IP_REACHABILITY_LOST:
6629                    if (DBG && message.obj != null) log((String) message.obj);
6630                    handleIpReachabilityLost();
6631                    transitionTo(mDisconnectingState);
6632                    break;
6633                case CMD_DISCONNECT:
6634                    mWifiNative.disconnect();
6635                    transitionTo(mDisconnectingState);
6636                    break;
6637                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6638                    if (message.arg1 == 1) {
6639                        mWifiNative.disconnect();
6640                        mTemporarilyDisconnectWifi = true;
6641                        transitionTo(mDisconnectingState);
6642                    }
6643                    break;
6644                case CMD_SET_OPERATIONAL_MODE:
6645                    if (message.arg1 != CONNECT_MODE) {
6646                        sendMessage(CMD_DISCONNECT);
6647                        deferMessage(message);
6648                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6649                            noteWifiDisabledWhileAssociated();
6650                        }
6651                    }
6652                    mWifiConfigManager.
6653                                setAndEnableLastSelectedConfiguration(
6654                                        WifiConfiguration.INVALID_NETWORK_ID);
6655                    break;
6656                    /* Ignore connection to same network */
6657                case WifiManager.CONNECT_NETWORK:
6658                    int netId = message.arg1;
6659                    if (mWifiInfo.getNetworkId() == netId) {
6660                        break;
6661                    }
6662                    return NOT_HANDLED;
6663                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6664                    mWifiInfo.setBSSID((String) message.obj);
6665                    mLastNetworkId = message.arg1;
6666                    mWifiInfo.setNetworkId(mLastNetworkId);
6667                    if(!mLastBssid.equals((String) message.obj)) {
6668                        mLastBssid = (String) message.obj;
6669                        sendNetworkStateChangeBroadcast(mLastBssid);
6670                    }
6671                    break;
6672                case CMD_RSSI_POLL:
6673                    if (message.arg1 == mRssiPollToken) {
6674                        if (mWifiConfigManager.mEnableChipWakeUpWhenAssociated.get()) {
6675                            if (DBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
6676                            WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
6677                            if (stats != null) {
6678                                // Sanity check the results provided by driver
6679                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
6680                                        && (stats.rssi_mgmt == 0
6681                                        || stats.beacon_rx == 0)) {
6682                                    stats = null;
6683                                }
6684                            }
6685                            // Get Info and continue polling
6686                            fetchRssiLinkSpeedAndFrequencyNative();
6687                            mWifiScoreReport =
6688                                    WifiScoreReport.calculateScore(mWifiInfo,
6689                                                                   getCurrentWifiConfiguration(),
6690                                                                   mWifiConfigManager,
6691                                                                   mNetworkAgent,
6692                                                                   mWifiScoreReport,
6693                                                                   mAggressiveHandover,
6694                                                                   mWifiMetrics);
6695                        }
6696                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6697                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6698                        if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
6699                    } else {
6700                        // Polling has completed
6701                    }
6702                    break;
6703                case CMD_ENABLE_RSSI_POLL:
6704                    cleanWifiScore();
6705                    if (mWifiConfigManager.mEnableRssiPollWhenAssociated.get()) {
6706                        mEnableRssiPolling = (message.arg1 == 1);
6707                    } else {
6708                        mEnableRssiPolling = false;
6709                    }
6710                    mRssiPollToken++;
6711                    if (mEnableRssiPolling) {
6712                        // First poll
6713                        fetchRssiLinkSpeedAndFrequencyNative();
6714                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6715                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6716                    }
6717                    break;
6718                case WifiManager.RSSI_PKTCNT_FETCH:
6719                    RssiPacketCountInfo info = new RssiPacketCountInfo();
6720                    fetchRssiLinkSpeedAndFrequencyNative();
6721                    info.rssi = mWifiInfo.getRssi();
6722                    fetchPktcntNative(info);
6723                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
6724                    break;
6725                case CMD_DELAYED_NETWORK_DISCONNECT:
6726                    if (!linkDebouncing && mWifiConfigManager.mEnableLinkDebouncing) {
6727
6728                        // Ignore if we are not debouncing
6729                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
6730                                + message.arg1);
6731                        return HANDLED;
6732                    } else {
6733                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
6734                                + message.arg1);
6735
6736                        linkDebouncing = false;
6737                        // If we are still debouncing while this message comes,
6738                        // it means we were not able to reconnect within the alloted time
6739                        // = LINK_FLAPPING_DEBOUNCE_MSEC
6740                        // and thus, trigger a real disconnect
6741                        handleNetworkDisconnect();
6742                        transitionTo(mDisconnectedState);
6743                    }
6744                    break;
6745                case CMD_ASSOCIATED_BSSID:
6746                    if ((String) message.obj == null) {
6747                        logw("Associated command w/o BSSID");
6748                        break;
6749                    }
6750                    mLastBssid = (String) message.obj;
6751                    if (mLastBssid != null && (mWifiInfo.getBSSID() == null
6752                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
6753                        mWifiInfo.setBSSID((String) message.obj);
6754                        sendNetworkStateChangeBroadcast(mLastBssid);
6755                    }
6756                    break;
6757                case CMD_START_RSSI_MONITORING_OFFLOAD:
6758                case CMD_RSSI_THRESHOLD_BREACH:
6759                    byte currRssi = (byte) message.arg1;
6760                    processRssiThreshold(currRssi, message.what);
6761                    break;
6762                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
6763                    stopRssiMonitoringOffload();
6764                    break;
6765                case CMD_RESET_SIM_NETWORKS:
6766                    if (message.arg1 == 0 // sim was removed
6767                            && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6768                        WifiConfiguration config =
6769                                mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6770                        if (TelephonyUtil.isSimConfig(config)) {
6771                            mWifiNative.disconnect();
6772                            transitionTo(mDisconnectingState);
6773                        }
6774                    }
6775                    /* allow parent state to reset data for other networks */
6776                    return NOT_HANDLED;
6777                default:
6778                    return NOT_HANDLED;
6779            }
6780
6781            return HANDLED;
6782        }
6783    }
6784
6785    class ObtainingIpState extends State {
6786        @Override
6787        public void enter() {
6788            if (DBG) {
6789                String key = "";
6790                if (getCurrentWifiConfiguration() != null) {
6791                    key = getCurrentWifiConfiguration().configKey();
6792                }
6793                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
6794                        + " " + key + " "
6795                        + " roam=" + mAutoRoaming
6796                        + " static=" + mWifiConfigManager.isUsingStaticIp(mLastNetworkId)
6797                        + " watchdog= " + obtainingIpWatchdogCount);
6798            }
6799
6800            // Reset link Debouncing, indicating we have successfully re-connected to the AP
6801            // We might still be roaming
6802            linkDebouncing = false;
6803
6804            // Send event to CM & network change broadcast
6805            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
6806
6807            // We must clear the config BSSID, as the wifi chipset may decide to roam
6808            // from this point on and having the BSSID specified in the network block would
6809            // cause the roam to fail and the device to disconnect.
6810            clearCurrentConfigBSSID("ObtainingIpAddress");
6811
6812            // Stop IpManager in case we're switching from DHCP to static
6813            // configuration or vice versa.
6814            //
6815            // TODO: Only ever enter this state the first time we connect to a
6816            // network, never on switching between static configuration and
6817            // DHCP. When we transition from static configuration to DHCP in
6818            // particular, we must tell ConnectivityService that we're
6819            // disconnected, because DHCP might take a long time during which
6820            // connectivity APIs such as getActiveNetworkInfo should not return
6821            // CONNECTED.
6822            stopIpManager();
6823
6824            mIpManager.setHttpProxy(mWifiConfigManager.getProxyProperties(mLastNetworkId));
6825            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
6826                mIpManager.setTcpBufferSizes(mTcpBufferSizes);
6827            }
6828
6829            if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
6830                final IpManager.ProvisioningConfiguration prov =
6831                        mIpManager.buildProvisioningConfiguration()
6832                            .withPreDhcpAction()
6833                            .withApfCapabilities(mWifiNative.getApfCapabilities())
6834                            .build();
6835                mIpManager.startProvisioning(prov);
6836                obtainingIpWatchdogCount++;
6837                logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
6838                // Get Link layer stats so as we get fresh tx packet counters
6839                getWifiLinkLayerStats(true);
6840                sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
6841                        obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
6842            } else {
6843                StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(
6844                        mLastNetworkId);
6845                if (config.ipAddress == null) {
6846                    logd("Static IP lacks address");
6847                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
6848                } else {
6849                    final IpManager.ProvisioningConfiguration prov =
6850                            mIpManager.buildProvisioningConfiguration()
6851                                .withStaticConfiguration(config)
6852                                .withApfCapabilities(mWifiNative.getApfCapabilities())
6853                                .build();
6854                    mIpManager.startProvisioning(prov);
6855                }
6856            }
6857        }
6858
6859        @Override
6860        public boolean processMessage(Message message) {
6861            logStateAndMessage(message, this);
6862
6863            switch(message.what) {
6864                case CMD_AUTO_CONNECT:
6865                case CMD_AUTO_ROAM:
6866                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6867                    break;
6868                case WifiManager.SAVE_NETWORK:
6869                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
6870                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6871                    deferMessage(message);
6872                    break;
6873                    /* Defer any power mode changes since we must keep active power mode at DHCP */
6874
6875                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6876                    reportConnectionAttemptEnd(
6877                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6878                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6879                    return NOT_HANDLED;
6880                case CMD_SET_HIGH_PERF_MODE:
6881                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6882                    deferMessage(message);
6883                    break;
6884                    /* Defer scan request since we should not switch to other channels at DHCP */
6885                case CMD_START_SCAN:
6886                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6887                    deferMessage(message);
6888                    break;
6889                case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
6890                    if (message.arg1 == obtainingIpWatchdogCount) {
6891                        logd("ObtainingIpAddress: Watchdog Triggered, count="
6892                                + obtainingIpWatchdogCount);
6893                        handleIpConfigurationLost();
6894                        transitionTo(mDisconnectingState);
6895                        break;
6896                    }
6897                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6898                    break;
6899                default:
6900                    return NOT_HANDLED;
6901            }
6902            return HANDLED;
6903        }
6904    }
6905
6906    private void sendConnectedState() {
6907        // If this network was explicitly selected by the user, evaluate whether to call
6908        // explicitlySelected() so the system can treat it appropriately.
6909        WifiConfiguration config = getCurrentWifiConfiguration();
6910        if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
6911            boolean prompt =
6912                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
6913            if (DBG) {
6914                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
6915            }
6916            if (prompt) {
6917                // Selected by the user via Settings or QuickSettings. If this network has Internet
6918                // access, switch to it. Otherwise, switch to it only if the user confirms that they
6919                // really want to switch, or has already confirmed and selected "Don't ask again".
6920                if (DBG) {
6921                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
6922                }
6923                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
6924            }
6925        }
6926
6927        setNetworkDetailedState(DetailedState.CONNECTED);
6928        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
6929        sendNetworkStateChangeBroadcast(mLastBssid);
6930    }
6931
6932    class RoamingState extends State {
6933        boolean mAssociated;
6934        @Override
6935        public void enter() {
6936            if (DBG) {
6937                log("RoamingState Enter"
6938                        + " mScreenOn=" + mScreenOn );
6939            }
6940
6941            // Make sure we disconnect if roaming fails
6942            roamWatchdogCount++;
6943            logd("Start Roam Watchdog " + roamWatchdogCount);
6944            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
6945                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
6946            mAssociated = false;
6947        }
6948        @Override
6949        public boolean processMessage(Message message) {
6950            logStateAndMessage(message, this);
6951            WifiConfiguration config;
6952            switch (message.what) {
6953                case CMD_IP_CONFIGURATION_LOST:
6954                    config = getCurrentWifiConfiguration();
6955                    if (config != null) {
6956                        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
6957                        mWifiConfigManager.noteRoamingFailure(config,
6958                                WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
6959                    }
6960                    return NOT_HANDLED;
6961                case CMD_UNWANTED_NETWORK:
6962                    if (DBG) log("Roaming and CS doesnt want the network -> ignore");
6963                    return HANDLED;
6964                case CMD_SET_OPERATIONAL_MODE:
6965                    if (message.arg1 != CONNECT_MODE) {
6966                        deferMessage(message);
6967                    }
6968                    break;
6969                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6970                    /**
6971                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
6972                     * before NETWORK_DISCONNECTION_EVENT
6973                     * And there is an associated BSSID corresponding to our target BSSID, then
6974                     * we have missed the network disconnection, transition to mDisconnectedState
6975                     * and handle the rest of the events there.
6976                     */
6977                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6978                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
6979                            || stateChangeResult.state == SupplicantState.INACTIVE
6980                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
6981                        if (DBG) {
6982                            log("STATE_CHANGE_EVENT in roaming state "
6983                                    + stateChangeResult.toString() );
6984                        }
6985                        if (stateChangeResult.BSSID != null
6986                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
6987                            handleNetworkDisconnect();
6988                            transitionTo(mDisconnectedState);
6989                        }
6990                    }
6991                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
6992                        // We completed the layer2 roaming part
6993                        mAssociated = true;
6994                        if (stateChangeResult.BSSID != null) {
6995                            mTargetRoamBSSID = (String) stateChangeResult.BSSID;
6996                        }
6997                    }
6998                    break;
6999                case CMD_ROAM_WATCHDOG_TIMER:
7000                    if (roamWatchdogCount == message.arg1) {
7001                        if (DBG) log("roaming watchdog! -> disconnect");
7002                        mWifiMetrics.endConnectionEvent(
7003                                WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
7004                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7005                        mRoamFailCount++;
7006                        handleNetworkDisconnect();
7007                        mWifiNative.disconnect();
7008                        transitionTo(mDisconnectedState);
7009                    }
7010                    break;
7011                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7012                    if (mAssociated) {
7013                        if (DBG) log("roaming and Network connection established");
7014                        mLastNetworkId = message.arg1;
7015                        mLastBssid = (String) message.obj;
7016                        mWifiInfo.setBSSID(mLastBssid);
7017                        mWifiInfo.setNetworkId(mLastNetworkId);
7018                        if (mWifiConnectivityManager != null) {
7019                            mWifiConnectivityManager.trackBssid(mLastBssid, true);
7020                        }
7021                        sendNetworkStateChangeBroadcast(mLastBssid);
7022
7023                        // Successful framework roam! (probably)
7024                        reportConnectionAttemptEnd(
7025                                WifiMetrics.ConnectionEvent.FAILURE_NONE,
7026                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7027
7028                        // We must clear the config BSSID, as the wifi chipset may decide to roam
7029                        // from this point on and having the BSSID specified by QNS would cause
7030                        // the roam to fail and the device to disconnect.
7031                        // When transition from RoamingState to DisconnectingState or
7032                        // DisconnectedState, the config BSSID is cleared by
7033                        // handleNetworkDisconnect().
7034                        clearCurrentConfigBSSID("RoamingCompleted");
7035
7036                        // We used to transition to ObtainingIpState in an
7037                        // attempt to do DHCPv4 RENEWs on framework roams.
7038                        // DHCP can take too long to time out, and we now rely
7039                        // upon IpManager's use of IpReachabilityMonitor to
7040                        // confirm our current network configuration.
7041                        //
7042                        // mIpManager.confirmConfiguration() is called within
7043                        // the handling of SupplicantState.COMPLETED.
7044                        transitionTo(mConnectedState);
7045                    } else {
7046                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7047                    }
7048                    break;
7049                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7050                    // Throw away but only if it corresponds to the network we're roaming to
7051                    String bssid = (String) message.obj;
7052                    if (true) {
7053                        String target = "";
7054                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
7055                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
7056                                + " BSSID=" + bssid
7057                                + " target=" + target);
7058                    }
7059                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
7060                        handleNetworkDisconnect();
7061                        transitionTo(mDisconnectedState);
7062                    }
7063                    break;
7064                case WifiMonitor.SSID_TEMP_DISABLED:
7065                    // Auth error while roaming
7066                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
7067                            + " id=" + Integer.toString(message.arg1)
7068                            + " isRoaming=" + isRoaming()
7069                            + " roam=" + mAutoRoaming);
7070                    if (message.arg1 == mLastNetworkId) {
7071                        config = getCurrentWifiConfiguration();
7072                        if (config != null) {
7073                            mWifiLogger.captureBugReportData(
7074                                    WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
7075                            mWifiConfigManager.noteRoamingFailure(config,
7076                                    WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
7077                        }
7078                        handleNetworkDisconnect();
7079                        transitionTo(mDisconnectingState);
7080                    }
7081                    return NOT_HANDLED;
7082                case CMD_START_SCAN:
7083                    deferMessage(message);
7084                    break;
7085                default:
7086                    return NOT_HANDLED;
7087            }
7088            return HANDLED;
7089        }
7090
7091        @Override
7092        public void exit() {
7093            logd("WifiStateMachine: Leaving Roaming state");
7094        }
7095    }
7096
7097    class ConnectedState extends State {
7098        @Override
7099        public void enter() {
7100            String address;
7101            updateDefaultRouteMacAddress(1000);
7102            if (DBG) {
7103                log("Enter ConnectedState "
7104                       + " mScreenOn=" + mScreenOn);
7105            }
7106
7107            if (mWifiConnectivityManager != null) {
7108                mWifiConnectivityManager.handleConnectionStateChanged(
7109                        WifiConnectivityManager.WIFI_STATE_CONNECTED);
7110            }
7111            registerConnected();
7112            lastConnectAttemptTimestamp = 0;
7113            targetWificonfiguration = null;
7114            // Paranoia
7115            linkDebouncing = false;
7116
7117            // Not roaming anymore
7118            mAutoRoaming = false;
7119
7120            if (testNetworkDisconnect) {
7121                testNetworkDisconnectCounter++;
7122                logd("ConnectedState Enter start disconnect test " +
7123                        testNetworkDisconnectCounter);
7124                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
7125                        testNetworkDisconnectCounter, 0), 15000);
7126            }
7127
7128            // Reenable all networks, allow for hidden networks to be scanned
7129            mWifiConfigManager.enableAllNetworks();
7130
7131            mLastDriverRoamAttempt = 0;
7132            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
7133            mWifiLastResortWatchdog.connectedStateTransition(true);
7134        }
7135        @Override
7136        public boolean processMessage(Message message) {
7137            WifiConfiguration config = null;
7138            logStateAndMessage(message, this);
7139
7140            switch (message.what) {
7141                case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
7142                    updateAssociatedScanPermission();
7143                    break;
7144                case CMD_UNWANTED_NETWORK:
7145                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
7146                        mWifiNative.disconnect();
7147                        transitionTo(mDisconnectingState);
7148                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
7149                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
7150                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
7151                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
7152                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
7153                        config = getCurrentWifiConfiguration();
7154                        if (config != null) {
7155                            // Disable autojoin
7156                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
7157                                config.validatedInternetAccess = false;
7158                                // Clear last-selected status, as being last-selected also avoids
7159                                // disabling auto-join.
7160                                if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
7161                                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(
7162                                        WifiConfiguration.INVALID_NETWORK_ID);
7163                                }
7164                                mWifiConfigManager.updateNetworkSelectionStatus(config,
7165                                        WifiConfiguration.NetworkSelectionStatus
7166                                        .DISABLED_NO_INTERNET);
7167                            }
7168                            config.numNoInternetAccessReports += 1;
7169                            mWifiConfigManager.writeKnownNetworkHistory();
7170                        }
7171                    }
7172                    return HANDLED;
7173                case CMD_NETWORK_STATUS:
7174                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
7175                        config = getCurrentWifiConfiguration();
7176                        if (config != null) {
7177                            // re-enable autojoin
7178                            config.numNoInternetAccessReports = 0;
7179                            config.validatedInternetAccess = true;
7180                            mWifiConfigManager.writeKnownNetworkHistory();
7181                        }
7182                    }
7183                    return HANDLED;
7184                case CMD_ACCEPT_UNVALIDATED:
7185                    boolean accept = (message.arg1 != 0);
7186                    config = getCurrentWifiConfiguration();
7187                    if (config != null) {
7188                        config.noInternetAccessExpected = accept;
7189                        mWifiConfigManager.writeKnownNetworkHistory();
7190                    }
7191                    return HANDLED;
7192                case CMD_TEST_NETWORK_DISCONNECT:
7193                    // Force a disconnect
7194                    if (message.arg1 == testNetworkDisconnectCounter) {
7195                        mWifiNative.disconnect();
7196                    }
7197                    break;
7198                case CMD_ASSOCIATED_BSSID:
7199                    // ASSOCIATING to a new BSSID while already connected, indicates
7200                    // that driver is roaming
7201                    mLastDriverRoamAttempt = System.currentTimeMillis();
7202                    return NOT_HANDLED;
7203                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7204                    long lastRoam = 0;
7205                    reportConnectionAttemptEnd(
7206                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
7207                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
7208                    if (mLastDriverRoamAttempt != 0) {
7209                        // Calculate time since last driver roam attempt
7210                        lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
7211                        mLastDriverRoamAttempt = 0;
7212                    }
7213                    if (unexpectedDisconnectedReason(message.arg2)) {
7214                        mWifiLogger.captureBugReportData(
7215                                WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
7216                    }
7217                    config = getCurrentWifiConfiguration();
7218                    if (mScreenOn
7219                            && !linkDebouncing
7220                            && config != null
7221                            && config.getNetworkSelectionStatus().isNetworkEnabled()
7222                            && !mWifiConfigManager.isLastSelectedConfiguration(config)
7223                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
7224                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
7225                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
7226                                    && mWifiInfo.getRssi() >
7227                                    WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
7228                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
7229                                    && mWifiInfo.getRssi() >
7230                                    mWifiConfigManager.mThresholdQualifiedRssi5.get()))) {
7231                        // Start de-bouncing the L2 disconnection:
7232                        // this L2 disconnection might be spurious.
7233                        // Hence we allow 4 seconds for the state machine to try
7234                        // to reconnect, go thru the
7235                        // roaming cycle and enter Obtaining IP address
7236                        // before signalling the disconnect to ConnectivityService and L3
7237                        startScanForConfiguration(getCurrentWifiConfiguration());
7238                        linkDebouncing = true;
7239
7240                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
7241                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
7242                        if (DBG) {
7243                            log("NETWORK_DISCONNECTION_EVENT in connected state"
7244                                    + " BSSID=" + mWifiInfo.getBSSID()
7245                                    + " RSSI=" + mWifiInfo.getRssi()
7246                                    + " freq=" + mWifiInfo.getFrequency()
7247                                    + " reason=" + message.arg2
7248                                    + " -> debounce");
7249                        }
7250                        return HANDLED;
7251                    } else {
7252                        if (DBG) {
7253                            log("NETWORK_DISCONNECTION_EVENT in connected state"
7254                                    + " BSSID=" + mWifiInfo.getBSSID()
7255                                    + " RSSI=" + mWifiInfo.getRssi()
7256                                    + " freq=" + mWifiInfo.getFrequency()
7257                                    + " was debouncing=" + linkDebouncing
7258                                    + " reason=" + message.arg2
7259                                    + " Network Selection Status=" + (config == null ? "Unavailable"
7260                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
7261                        }
7262                    }
7263                    break;
7264                case CMD_AUTO_ROAM:
7265                    // Clear the driver roam indication since we are attempting a framework roam
7266                    mLastDriverRoamAttempt = 0;
7267
7268                    /*<TODO> 2016-02-24
7269                        Fix CMD_AUTO_ROAM to use the candidate (message.arg1) networkID, rather than
7270                        the old networkID.
7271                        The current code only handles roaming between BSSIDs on the same networkID,
7272                        and will break for roams between different (but linked) networkIDs. This
7273                        case occurs for DBDC roaming, and the CMD_AUTO_ROAM sent due to it will
7274                        fail.
7275                    */
7276                    /* Connect command coming from auto-join */
7277                    ScanResult candidate = (ScanResult)message.obj;
7278                    String bssid = "any";
7279                    if (candidate != null) {
7280                        bssid = candidate.BSSID;
7281                    }
7282                    int netId = message.arg1;
7283                    if (netId == WifiConfiguration.INVALID_NETWORK_ID) {
7284                        loge("AUTO_ROAM and no config, bail out...");
7285                        break;
7286                    } else {
7287                        config = mWifiConfigManager.getWifiConfiguration(netId);
7288                        if (config == null) {
7289                          loge("AUTO_ROAM and invalid netowrk ID, bail out...");
7290                          break;
7291                        }
7292                    }
7293
7294                    setTargetBssid(config, bssid);
7295                    mTargetNetworkId = netId;
7296
7297                    logd("CMD_AUTO_ROAM sup state "
7298                            + mSupplicantStateTracker.getSupplicantStateName()
7299                            + " my state " + getCurrentState().getName()
7300                            + " nid=" + Integer.toString(netId)
7301                            + " config " + config.configKey()
7302                            + " targetRoamBSSID " + mTargetRoamBSSID);
7303
7304                    /* Determine if this is a regular roam (between BSSIDs sharing the same SSID),
7305                       or a DBDC roam (between 2.4 & 5GHz networks on different SSID's, but with
7306                       matching 16 byte BSSID prefixes):
7307                     */
7308                    WifiConfiguration currentConfig = getCurrentWifiConfiguration();
7309                    if (currentConfig != null && currentConfig.isLinked(config)) {
7310                        // This is dual band roaming
7311                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
7312                                WifiMetricsProto.ConnectionEvent.ROAM_DBDC);
7313                    } else {
7314                        // This is regular roaming
7315                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
7316                                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
7317                    }
7318
7319                    if (deferForUserInput(message, netId, false)) {
7320                        reportConnectionAttemptEnd(
7321                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7322                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7323                        break;
7324                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
7325                            WifiConfiguration.USER_BANNED) {
7326                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7327                                WifiManager.NOT_AUTHORIZED);
7328                        reportConnectionAttemptEnd(
7329                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7330                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7331                        break;
7332                    }
7333
7334                    boolean ret = false;
7335                    if (mLastNetworkId != netId) {
7336                        if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
7337                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
7338                            ret = true;
7339                        }
7340                    } else {
7341                        ret = mWifiNative.reassociate();
7342                    }
7343                    if (ret) {
7344                        lastConnectAttemptTimestamp = System.currentTimeMillis();
7345                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
7346
7347                        // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
7348                        mAutoRoaming = true;
7349                        transitionTo(mRoamingState);
7350
7351                    } else {
7352                        loge("Failed to connect config: " + config + " netId: " + netId);
7353                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7354                                WifiManager.ERROR);
7355                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7356                        reportConnectionAttemptEnd(
7357                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
7358                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7359                        break;
7360                    }
7361                    break;
7362                case CMD_START_IP_PACKET_OFFLOAD: {
7363                        int slot = message.arg1;
7364                        int intervalSeconds = message.arg2;
7365                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
7366                        byte[] dstMac;
7367                        try {
7368                            InetAddress gateway = RouteInfo.selectBestRoute(
7369                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
7370                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
7371                            dstMac = macAddressFromString(dstMacStr);
7372                        } catch (NullPointerException|IllegalArgumentException e) {
7373                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
7374                            mNetworkAgent.onPacketKeepaliveEvent(slot,
7375                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
7376                            break;
7377                        }
7378                        pkt.dstMac = dstMac;
7379                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
7380                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
7381                        break;
7382                    }
7383                default:
7384                    return NOT_HANDLED;
7385            }
7386            return HANDLED;
7387        }
7388
7389        @Override
7390        public void exit() {
7391            logd("WifiStateMachine: Leaving Connected state");
7392            if (mWifiConnectivityManager != null) {
7393                mWifiConnectivityManager.handleConnectionStateChanged(
7394                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7395            }
7396
7397            mLastDriverRoamAttempt = 0;
7398            mWhiteListedSsids = null;
7399            mWifiLastResortWatchdog.connectedStateTransition(false);
7400        }
7401    }
7402
7403    class DisconnectingState extends State {
7404
7405        @Override
7406        public void enter() {
7407
7408            if (DBG) {
7409                logd(" Enter DisconnectingState State screenOn=" + mScreenOn);
7410            }
7411
7412            // Make sure we disconnect: we enter this state prior to connecting to a new
7413            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
7414            // event which in this case will be indicating that supplicant started to associate.
7415            // In some cases supplicant doesn't ignore the connect requests (it might not
7416            // find the target SSID in its cache),
7417            // Therefore we end up stuck that state, hence the need for the watchdog.
7418            disconnectingWatchdogCount++;
7419            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
7420            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
7421                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
7422        }
7423
7424        @Override
7425        public boolean processMessage(Message message) {
7426            logStateAndMessage(message, this);
7427            switch (message.what) {
7428                case CMD_SET_OPERATIONAL_MODE:
7429                    if (message.arg1 != CONNECT_MODE) {
7430                        deferMessage(message);
7431                    }
7432                    break;
7433                case CMD_START_SCAN:
7434                    deferMessage(message);
7435                    return HANDLED;
7436                case CMD_DISCONNECT:
7437                    if (DBG) log("Ignore CMD_DISCONNECT when already disconnecting.");
7438                    break;
7439                case CMD_DISCONNECTING_WATCHDOG_TIMER:
7440                    if (disconnectingWatchdogCount == message.arg1) {
7441                        if (DBG) log("disconnecting watchdog! -> disconnect");
7442                        handleNetworkDisconnect();
7443                        transitionTo(mDisconnectedState);
7444                    }
7445                    break;
7446                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7447                    /**
7448                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
7449                     * we have missed the network disconnection, transition to mDisconnectedState
7450                     * and handle the rest of the events there
7451                     */
7452                    deferMessage(message);
7453                    handleNetworkDisconnect();
7454                    transitionTo(mDisconnectedState);
7455                    break;
7456                default:
7457                    return NOT_HANDLED;
7458            }
7459            return HANDLED;
7460        }
7461    }
7462
7463    class DisconnectedState extends State {
7464        @Override
7465        public void enter() {
7466            // We dont scan frequently if this is a temporary disconnect
7467            // due to p2p
7468            if (mTemporarilyDisconnectWifi) {
7469                mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
7470                return;
7471            }
7472
7473            if (DBG) {
7474                logd(" Enter DisconnectedState screenOn=" + mScreenOn);
7475            }
7476
7477            /** clear the roaming state, if we were roaming, we failed */
7478            mAutoRoaming = false;
7479
7480            if (mWifiConnectivityManager != null) {
7481                mWifiConnectivityManager.handleConnectionStateChanged(
7482                        WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
7483            }
7484
7485            /**
7486             * If we have no networks saved, the supplicant stops doing the periodic scan.
7487             * The scans are useful to notify the user of the presence of an open network.
7488             * Note that these are not wake up scans.
7489             */
7490            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
7491                    && mWifiConfigManager.getSavedNetworks().size() == 0) {
7492                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7493                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7494            }
7495
7496            mDisconnectedTimeStamp = System.currentTimeMillis();
7497        }
7498        @Override
7499        public boolean processMessage(Message message) {
7500            boolean ret = HANDLED;
7501
7502            logStateAndMessage(message, this);
7503
7504            switch (message.what) {
7505                case CMD_NO_NETWORKS_PERIODIC_SCAN:
7506                    if (mP2pConnected.get()) break;
7507                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
7508                            mWifiConfigManager.getSavedNetworks().size() == 0) {
7509                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, WIFI_WORK_SOURCE);
7510                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7511                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7512                    }
7513                    break;
7514                case WifiManager.FORGET_NETWORK:
7515                case CMD_REMOVE_NETWORK:
7516                case CMD_REMOVE_APP_CONFIGURATIONS:
7517                case CMD_REMOVE_USER_CONFIGURATIONS:
7518                    // Set up a delayed message here. After the forget/remove is handled
7519                    // the handled delayed message will determine if there is a need to
7520                    // scan and continue
7521                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7522                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7523                    ret = NOT_HANDLED;
7524                    break;
7525                case CMD_SET_OPERATIONAL_MODE:
7526                    if (message.arg1 != CONNECT_MODE) {
7527                        mOperationalMode = message.arg1;
7528                        mWifiConfigManager.disableAllNetworksNative();
7529                        if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
7530                            mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
7531                            setWifiState(WIFI_STATE_DISABLED);
7532                        }
7533                        transitionTo(mScanModeState);
7534                    }
7535                    mWifiConfigManager.
7536                            setAndEnableLastSelectedConfiguration(
7537                                    WifiConfiguration.INVALID_NETWORK_ID);
7538                    break;
7539                case CMD_DISCONNECT:
7540                    if (SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {
7541                        if (DBG) {
7542                            log("CMD_DISCONNECT when supplicant is connecting - do not ignore");
7543                        }
7544                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
7545                                WifiConfiguration.INVALID_NETWORK_ID);
7546                        mWifiNative.disconnect();
7547                        break;
7548                    }
7549                    if (DBG) log("Ignore CMD_DISCONNECT when already disconnected.");
7550                    break;
7551                /* Ignore network disconnect */
7552                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7553                    // Interpret this as an L2 connection failure
7554                    break;
7555                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7556                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7557                    if (DBG) {
7558                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
7559                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
7560                                + " debouncing=" + linkDebouncing);
7561                    }
7562                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
7563                    /* ConnectModeState does the rest of the handling */
7564                    ret = NOT_HANDLED;
7565                    break;
7566                case CMD_START_SCAN:
7567                    if (!checkOrDeferScanAllowed(message)) {
7568                        // The scan request was rescheduled
7569                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
7570                        return HANDLED;
7571                    }
7572
7573                    ret = NOT_HANDLED;
7574                    break;
7575                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
7576                    NetworkInfo info = (NetworkInfo) message.obj;
7577                    mP2pConnected.set(info.isConnected());
7578                    if (mP2pConnected.get()) {
7579                        int defaultInterval = mContext.getResources().getInteger(
7580                                R.integer.config_wifi_scan_interval_p2p_connected);
7581                        long scanIntervalMs = mFacade.getLongSetting(mContext,
7582                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
7583                                defaultInterval);
7584                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
7585                    } else if (mWifiConfigManager.getSavedNetworks().size() == 0) {
7586                        if (DBG) log("Turn on scanning after p2p disconnected");
7587                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7588                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7589                    }
7590                    break;
7591                case CMD_RECONNECT:
7592                case CMD_REASSOCIATE:
7593                    if (mTemporarilyDisconnectWifi) {
7594                        // Drop a third party reconnect/reassociate if STA is
7595                        // temporarily disconnected for p2p
7596                        break;
7597                    } else {
7598                        // ConnectModeState handles it
7599                        ret = NOT_HANDLED;
7600                    }
7601                    break;
7602                case CMD_SCREEN_STATE_CHANGED:
7603                    handleScreenStateChanged(message.arg1 != 0);
7604                    break;
7605                default:
7606                    ret = NOT_HANDLED;
7607            }
7608            return ret;
7609        }
7610
7611        @Override
7612        public void exit() {
7613            if (mWifiConnectivityManager != null) {
7614                mWifiConnectivityManager.handleConnectionStateChanged(
7615                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7616            }
7617        }
7618    }
7619
7620    class WpsRunningState extends State {
7621        // Tracks the source to provide a reply
7622        private Message mSourceMessage;
7623        @Override
7624        public void enter() {
7625            mSourceMessage = Message.obtain(getCurrentMessage());
7626        }
7627        @Override
7628        public boolean processMessage(Message message) {
7629            logStateAndMessage(message, this);
7630
7631            switch (message.what) {
7632                case WifiMonitor.WPS_SUCCESS_EVENT:
7633                    // Ignore intermediate success, wait for full connection
7634                    break;
7635                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7636                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
7637                    mSourceMessage.recycle();
7638                    mSourceMessage = null;
7639                    deferMessage(message);
7640                    transitionTo(mDisconnectedState);
7641                    break;
7642                case WifiMonitor.WPS_OVERLAP_EVENT:
7643                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7644                            WifiManager.WPS_OVERLAP_ERROR);
7645                    mSourceMessage.recycle();
7646                    mSourceMessage = null;
7647                    transitionTo(mDisconnectedState);
7648                    break;
7649                case WifiMonitor.WPS_FAIL_EVENT:
7650                    // Arg1 has the reason for the failure
7651                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
7652                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
7653                        mSourceMessage.recycle();
7654                        mSourceMessage = null;
7655                        transitionTo(mDisconnectedState);
7656                    } else {
7657                        if (DBG) log("Ignore unspecified fail event during WPS connection");
7658                    }
7659                    break;
7660                case WifiMonitor.WPS_TIMEOUT_EVENT:
7661                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7662                            WifiManager.WPS_TIMED_OUT);
7663                    mSourceMessage.recycle();
7664                    mSourceMessage = null;
7665                    transitionTo(mDisconnectedState);
7666                    break;
7667                case WifiManager.START_WPS:
7668                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
7669                    break;
7670                case WifiManager.CANCEL_WPS:
7671                    if (mWifiNative.cancelWps()) {
7672                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
7673                    } else {
7674                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
7675                    }
7676                    transitionTo(mDisconnectedState);
7677                    break;
7678                /**
7679                 * Defer all commands that can cause connections to a different network
7680                 * or put the state machine out of connect mode
7681                 */
7682                case CMD_STOP_DRIVER:
7683                case CMD_SET_OPERATIONAL_MODE:
7684                case WifiManager.CONNECT_NETWORK:
7685                case CMD_ENABLE_NETWORK:
7686                case CMD_RECONNECT:
7687                case CMD_REASSOCIATE:
7688                case CMD_ENABLE_ALL_NETWORKS:
7689                    deferMessage(message);
7690                    break;
7691                case CMD_AUTO_CONNECT:
7692                case CMD_AUTO_ROAM:
7693                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7694                    return HANDLED;
7695                case CMD_START_SCAN:
7696                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7697                    return HANDLED;
7698                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7699                    if (DBG) log("Network connection lost");
7700                    handleNetworkDisconnect();
7701                    break;
7702                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
7703                    if (DBG) log("Ignore Assoc reject event during WPS Connection");
7704                    break;
7705                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
7706                    // Disregard auth failure events during WPS connection. The
7707                    // EAP sequence is retried several times, and there might be
7708                    // failures (especially for wps pin). We will get a WPS_XXX
7709                    // event at the end of the sequence anyway.
7710                    if (DBG) log("Ignore auth failure during WPS connection");
7711                    break;
7712                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7713                    // Throw away supplicant state changes when WPS is running.
7714                    // We will start getting supplicant state changes once we get
7715                    // a WPS success or failure
7716                    break;
7717                default:
7718                    return NOT_HANDLED;
7719            }
7720            return HANDLED;
7721        }
7722
7723        @Override
7724        public void exit() {
7725            mWifiConfigManager.enableAllNetworks();
7726            mWifiConfigManager.loadConfiguredNetworks();
7727        }
7728    }
7729
7730    class SoftApState extends State {
7731        private SoftApManager mSoftApManager;
7732
7733        private class SoftApListener implements SoftApManager.Listener {
7734            @Override
7735            public void onStateChanged(int state, int reason) {
7736                if (state == WIFI_AP_STATE_DISABLED) {
7737                    sendMessage(CMD_AP_STOPPED);
7738                } else if (state == WIFI_AP_STATE_FAILED) {
7739                    sendMessage(CMD_START_AP_FAILURE);
7740                }
7741
7742                setWifiApState(state, reason);
7743            }
7744        }
7745
7746        @Override
7747        public void enter() {
7748            final Message message = getCurrentMessage();
7749            if (message.what == CMD_START_AP) {
7750                WifiConfiguration config = (WifiConfiguration) message.obj;
7751
7752                if (config == null) {
7753                    /**
7754                     * Configuration not provided in the command, fallback to use the current
7755                     * configuration.
7756                     */
7757                    config = mWifiApConfigStore.getApConfiguration();
7758                } else {
7759                    /* Update AP configuration. */
7760                    mWifiApConfigStore.setApConfiguration(config);
7761                }
7762
7763                checkAndSetConnectivityInstance();
7764                mSoftApManager = mFacade.makeSoftApManager(
7765                        mContext, getHandler().getLooper(), mWifiNative, mNwService,
7766                        mCm, mCountryCode.getCountryCode(),
7767                        mWifiApConfigStore.getAllowed2GChannel(),
7768                        new SoftApListener());
7769                mSoftApManager.start(config);
7770            } else {
7771                throw new RuntimeException("Illegal transition to SoftApState: " + message);
7772            }
7773        }
7774
7775        @Override
7776        public void exit() {
7777            mSoftApManager = null;
7778        }
7779
7780        @Override
7781        public boolean processMessage(Message message) {
7782            logStateAndMessage(message, this);
7783
7784            switch(message.what) {
7785                case CMD_START_AP:
7786                    /* Ignore start command when it is starting/started. */
7787                    break;
7788                case CMD_STOP_AP:
7789                    mSoftApManager.stop();
7790                    break;
7791                case CMD_START_AP_FAILURE:
7792                    transitionTo(mInitialState);
7793                    break;
7794                case CMD_AP_STOPPED:
7795                    transitionTo(mInitialState);
7796                    break;
7797                default:
7798                    return NOT_HANDLED;
7799            }
7800            return HANDLED;
7801        }
7802    }
7803
7804    /**
7805     * State machine initiated requests can have replyTo set to null indicating
7806     * there are no recepients, we ignore those reply actions.
7807     */
7808    private void replyToMessage(Message msg, int what) {
7809        if (msg.replyTo == null) return;
7810        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7811        mReplyChannel.replyToMessage(msg, dstMsg);
7812    }
7813
7814    private void replyToMessage(Message msg, int what, int arg1) {
7815        if (msg.replyTo == null) return;
7816        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7817        dstMsg.arg1 = arg1;
7818        mReplyChannel.replyToMessage(msg, dstMsg);
7819    }
7820
7821    private void replyToMessage(Message msg, int what, Object obj) {
7822        if (msg.replyTo == null) return;
7823        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7824        dstMsg.obj = obj;
7825        mReplyChannel.replyToMessage(msg, dstMsg);
7826    }
7827
7828    /**
7829     * arg2 on the source message has a unique id that needs to be retained in replies
7830     * to match the request
7831     * <p>see WifiManager for details
7832     */
7833    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
7834        Message msg = Message.obtain();
7835        msg.what = what;
7836        msg.arg2 = srcMsg.arg2;
7837        return msg;
7838    }
7839
7840    /**
7841     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
7842     * @param msg Must have a WifiConfiguration obj to succeed
7843     */
7844    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
7845            WifiConfiguration config) {
7846        if (config != null && config.preSharedKey != null) {
7847            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
7848            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
7849            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
7850                    wifiCredentialEventType);
7851            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
7852                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
7853        }
7854    }
7855
7856    private static int parseHex(char ch) {
7857        if ('0' <= ch && ch <= '9') {
7858            return ch - '0';
7859        } else if ('a' <= ch && ch <= 'f') {
7860            return ch - 'a' + 10;
7861        } else if ('A' <= ch && ch <= 'F') {
7862            return ch - 'A' + 10;
7863        } else {
7864            throw new NumberFormatException("" + ch + " is not a valid hex digit");
7865        }
7866    }
7867
7868    private byte[] parseHex(String hex) {
7869        /* This only works for good input; don't throw bad data at it */
7870        if (hex == null) {
7871            return new byte[0];
7872        }
7873
7874        if (hex.length() % 2 != 0) {
7875            throw new NumberFormatException(hex + " is not a valid hex string");
7876        }
7877
7878        byte[] result = new byte[(hex.length())/2 + 1];
7879        result[0] = (byte) ((hex.length())/2);
7880        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
7881            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
7882            byte b = (byte) (val & 0xFF);
7883            result[j] = b;
7884        }
7885
7886        return result;
7887    }
7888
7889    private static String makeHex(byte[] bytes) {
7890        StringBuilder sb = new StringBuilder();
7891        for (byte b : bytes) {
7892            sb.append(String.format("%02x", b));
7893        }
7894        return sb.toString();
7895    }
7896
7897    private static String makeHex(byte[] bytes, int from, int len) {
7898        StringBuilder sb = new StringBuilder();
7899        for (int i = 0; i < len; i++) {
7900            sb.append(String.format("%02x", bytes[from+i]));
7901        }
7902        return sb.toString();
7903    }
7904
7905    private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
7906
7907        int len = array1.length + array2.length + array3.length;
7908
7909        if (array1.length != 0) {
7910            len++;                      /* add another byte for size */
7911        }
7912
7913        if (array2.length != 0) {
7914            len++;                      /* add another byte for size */
7915        }
7916
7917        if (array3.length != 0) {
7918            len++;                      /* add another byte for size */
7919        }
7920
7921        byte[] result = new byte[len];
7922
7923        int index = 0;
7924        if (array1.length != 0) {
7925            result[index] = (byte) (array1.length & 0xFF);
7926            index++;
7927            for (byte b : array1) {
7928                result[index] = b;
7929                index++;
7930            }
7931        }
7932
7933        if (array2.length != 0) {
7934            result[index] = (byte) (array2.length & 0xFF);
7935            index++;
7936            for (byte b : array2) {
7937                result[index] = b;
7938                index++;
7939            }
7940        }
7941
7942        if (array3.length != 0) {
7943            result[index] = (byte) (array3.length & 0xFF);
7944            index++;
7945            for (byte b : array3) {
7946                result[index] = b;
7947                index++;
7948            }
7949        }
7950        return result;
7951    }
7952
7953    private static byte[] concatHex(byte[] array1, byte[] array2) {
7954
7955        int len = array1.length + array2.length;
7956
7957        byte[] result = new byte[len];
7958
7959        int index = 0;
7960        if (array1.length != 0) {
7961            for (byte b : array1) {
7962                result[index] = b;
7963                index++;
7964            }
7965        }
7966
7967        if (array2.length != 0) {
7968            for (byte b : array2) {
7969                result[index] = b;
7970                index++;
7971            }
7972        }
7973
7974        return result;
7975    }
7976
7977    // TODO move to TelephonyUtil, same with utilities above
7978    String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
7979        StringBuilder sb = new StringBuilder();
7980        for (String challenge : requestData) {
7981            if (challenge == null || challenge.isEmpty()) {
7982                continue;
7983            }
7984            logd("RAND = " + challenge);
7985
7986            byte[] rand = null;
7987            try {
7988                rand = parseHex(challenge);
7989            } catch (NumberFormatException e) {
7990                loge("malformed challenge");
7991                continue;
7992            }
7993
7994            String base64Challenge = android.util.Base64.encodeToString(
7995                    rand, android.util.Base64.NO_WRAP);
7996
7997            // Try USIM first for authentication.
7998            String tmResponse = tm.getIccAuthentication(tm.APPTYPE_USIM,
7999                    tm.AUTHTYPE_EAP_SIM, base64Challenge);
8000            if (tmResponse == null) {
8001                /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
8002                 */
8003                tmResponse = tm.getIccAuthentication(tm.APPTYPE_SIM,
8004                        tm.AUTHTYPE_EAP_SIM, base64Challenge);
8005            }
8006            logv("Raw Response - " + tmResponse);
8007
8008            if (tmResponse == null || tmResponse.length() <= 4) {
8009                loge("bad response - " + tmResponse);
8010                return null;
8011            }
8012
8013            byte[] result = android.util.Base64.decode(tmResponse, android.util.Base64.DEFAULT);
8014            logv("Hex Response -" + makeHex(result));
8015            int sres_len = result[0];
8016            if (sres_len >= result.length) {
8017                loge("malfomed response - " + tmResponse);
8018                return null;
8019            }
8020            String sres = makeHex(result, 1, sres_len);
8021            int kc_offset = 1 + sres_len;
8022            if (kc_offset >= result.length) {
8023                loge("malfomed response - " + tmResponse);
8024                return null;
8025            }
8026            int kc_len = result[kc_offset];
8027            if (kc_offset + kc_len > result.length) {
8028                loge("malfomed response - " + tmResponse);
8029                return null;
8030            }
8031            String kc = makeHex(result, 1 + kc_offset, kc_len);
8032            sb.append(":" + kc + ":" + sres);
8033            logv("kc:" + kc + " sres:" + sres);
8034        }
8035
8036        return sb.toString();
8037    }
8038
8039    // TODO move to TelephonyUtil
8040    void handleGsmAuthRequest(SimAuthRequestData requestData) {
8041        if (targetWificonfiguration == null
8042                || targetWificonfiguration.networkId == requestData.networkId) {
8043            logd("id matches targetWifiConfiguration");
8044        } else {
8045            logd("id does not match targetWifiConfiguration");
8046            return;
8047        }
8048
8049        TelephonyManager tm = (TelephonyManager)
8050                mContext.getSystemService(Context.TELEPHONY_SERVICE);
8051
8052        if (tm == null) {
8053            loge("could not get telephony manager");
8054            mWifiNative.simAuthFailedResponse(requestData.networkId);
8055            return;
8056        }
8057
8058        String response = getGsmSimAuthResponse(requestData.data, tm);
8059        if (response == null) {
8060            mWifiNative.simAuthFailedResponse(requestData.networkId);
8061        } else {
8062            logv("Supplicant Response -" + response);
8063            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
8064        }
8065    }
8066
8067    // TODO move to TelephonyUtil
8068    void handle3GAuthRequest(SimAuthRequestData requestData) {
8069        StringBuilder sb = new StringBuilder();
8070        byte[] rand = null;
8071        byte[] authn = null;
8072        String res_type = "UMTS-AUTH";
8073
8074        if (targetWificonfiguration == null
8075                || targetWificonfiguration.networkId == requestData.networkId) {
8076            logd("id matches targetWifiConfiguration");
8077        } else {
8078            logd("id does not match targetWifiConfiguration");
8079            return;
8080        }
8081        if (requestData.data.length == 2) {
8082            try {
8083                rand = parseHex(requestData.data[0]);
8084                authn = parseHex(requestData.data[1]);
8085            } catch (NumberFormatException e) {
8086                loge("malformed challenge");
8087            }
8088        } else {
8089               loge("malformed challenge");
8090        }
8091
8092        String tmResponse = "";
8093        if (rand != null && authn != null) {
8094            String base64Challenge = android.util.Base64.encodeToString(
8095                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
8096
8097            TelephonyManager tm = (TelephonyManager)
8098                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
8099            if (tm != null) {
8100                tmResponse = tm.getIccAuthentication(tm.APPTYPE_USIM,
8101                        tm.AUTHTYPE_EAP_AKA, base64Challenge);
8102                logv("Raw Response - " + tmResponse);
8103            } else {
8104                loge("could not get telephony manager");
8105            }
8106        }
8107
8108        boolean good_response = false;
8109        if (tmResponse != null && tmResponse.length() > 4) {
8110            byte[] result = android.util.Base64.decode(tmResponse,
8111                    android.util.Base64.DEFAULT);
8112            loge("Hex Response - " + makeHex(result));
8113            byte tag = result[0];
8114            if (tag == (byte) 0xdb) {
8115                logv("successful 3G authentication ");
8116                int res_len = result[1];
8117                String res = makeHex(result, 2, res_len);
8118                int ck_len = result[res_len + 2];
8119                String ck = makeHex(result, res_len + 3, ck_len);
8120                int ik_len = result[res_len + ck_len + 3];
8121                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
8122                sb.append(":" + ik + ":" + ck + ":" + res);
8123                logv("ik:" + ik + "ck:" + ck + " res:" + res);
8124                good_response = true;
8125            } else if (tag == (byte) 0xdc) {
8126                loge("synchronisation failure");
8127                int auts_len = result[1];
8128                String auts = makeHex(result, 2, auts_len);
8129                res_type = "UMTS-AUTS";
8130                sb.append(":" + auts);
8131                logv("auts:" + auts);
8132                good_response = true;
8133            } else {
8134                loge("bad response - unknown tag = " + tag);
8135            }
8136        } else {
8137            loge("bad response - " + tmResponse);
8138        }
8139
8140        if (good_response) {
8141            String response = sb.toString();
8142            logv("Supplicant Response -" + response);
8143            mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
8144        } else {
8145            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
8146        }
8147    }
8148
8149    /**
8150     * Automatically connect to the network specified
8151     *
8152     * @param networkId ID of the network to connect to
8153     * @param bssid BSSID of the network
8154     */
8155    public void autoConnectToNetwork(int networkId, String bssid) {
8156        synchronized (mWifiReqCountLock) {
8157            if (hasConnectionRequests()) {
8158                sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);
8159            }
8160        }
8161    }
8162
8163    /**
8164     * Automatically roam to the network specified
8165     *
8166     * @param networkId ID of the network to roam to
8167     * @param scanResult scan result which identifies the network to roam to
8168     */
8169    public void autoRoamToNetwork(int networkId, ScanResult scanResult) {
8170        sendMessage(CMD_AUTO_ROAM, networkId, 0, scanResult);
8171    }
8172
8173    /**
8174     * Dynamically turn on/off WifiConnectivityManager
8175     *
8176     * @param enabled true-enable; false-disable
8177     */
8178    public void enableWifiConnectivityManager(boolean enabled) {
8179        sendMessage(CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER, enabled ? 1 : 0);
8180    }
8181
8182    /**
8183     * @param reason reason code from supplicant on network disconnected event
8184     * @return true if this is a suspicious disconnect
8185     */
8186    static boolean unexpectedDisconnectedReason(int reason) {
8187        return reason == 2              // PREV_AUTH_NOT_VALID
8188                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
8189                || reason == 7          // FRAME_FROM_NONASSOC_STA
8190                || reason == 8          // STA_HAS_LEFT
8191                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
8192                || reason == 14         // MICHAEL_MIC_FAILURE
8193                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
8194                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
8195                || reason == 18         // GROUP_CIPHER_NOT_VALID
8196                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
8197                || reason == 23         // IEEE_802_1X_AUTH_FAILED
8198                || reason == 34;        // DISASSOC_LOW_ACK
8199    }
8200
8201    /**
8202     * Update WifiMetrics before dumping
8203     */
8204    void updateWifiMetrics() {
8205        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworksSize();
8206        int numOpenNetworks = 0;
8207        int numPersonalNetworks = 0;
8208        int numEnterpriseNetworks = 0;
8209        int numNetworksAddedByUser = 0;
8210        int numNetworksAddedByApps = 0;
8211        int numHiddenNetworks = 0;
8212        int numPasspoint = 0;
8213        for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) {
8214            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
8215                numOpenNetworks++;
8216            } else if (config.isEnterprise()) {
8217                numEnterpriseNetworks++;
8218            } else {
8219                numPersonalNetworks++;
8220            }
8221            if (config.selfAdded) {
8222                numNetworksAddedByUser++;
8223            } else {
8224                numNetworksAddedByApps++;
8225            }
8226            if (config.hiddenSSID) {
8227                numHiddenNetworks++;
8228            }
8229            if (config.isPasspoint()) {
8230                numPasspoint++;
8231            }
8232        }
8233        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
8234        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
8235        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
8236        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
8237        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
8238        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
8239        mWifiMetrics.setNumHiddenNetworks(numHiddenNetworks);
8240        mWifiMetrics.setNumPasspointNetworks(numPasspoint);
8241    }
8242
8243    private static String getLinkPropertiesSummary(LinkProperties lp) {
8244        List<String> attributes = new ArrayList(6);
8245        if (lp.hasIPv4Address()) {
8246            attributes.add("v4");
8247        }
8248        if (lp.hasIPv4DefaultRoute()) {
8249            attributes.add("v4r");
8250        }
8251        if (lp.hasIPv4DnsServer()) {
8252            attributes.add("v4dns");
8253        }
8254        if (lp.hasGlobalIPv6Address()) {
8255            attributes.add("v6");
8256        }
8257        if (lp.hasIPv6DefaultRoute()) {
8258            attributes.add("v6r");
8259        }
8260        if (lp.hasIPv6DnsServer()) {
8261            attributes.add("v6dns");
8262        }
8263
8264        return TextUtils.join(" ", attributes);
8265    }
8266
8267    private void wnmFrameReceived(WnmData event) {
8268        // %012x HS20-SUBSCRIPTION-REMEDIATION "%u %s", osu_method, url
8269        // %012x HS20-DEAUTH-IMMINENT-NOTICE "%u %u %s", code, reauth_delay, url
8270
8271        Intent intent = new Intent(WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION);
8272        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
8273
8274        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_BSSID, event.getBssid());
8275        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_URL, event.getUrl());
8276
8277        if (event.isDeauthEvent()) {
8278            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_ESS, event.isEss());
8279            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_DELAY, event.getDelay());
8280        } else {
8281            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_METHOD, event.getMethod());
8282            WifiConfiguration config = getCurrentWifiConfiguration();
8283            if (config != null && config.FQDN != null) {
8284                intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH,
8285                        mWifiConfigManager.matchProviderWithCurrentNetwork(config.FQDN));
8286            }
8287        }
8288        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
8289    }
8290
8291    /**
8292     * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
8293     * This should match the network config framework is attempting to connect to.
8294     */
8295    private String getTargetSsid() {
8296        WifiConfiguration currentConfig = mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
8297        if (currentConfig != null) {
8298            return currentConfig.SSID;
8299        }
8300        return null;
8301    }
8302
8303    /**
8304     * Check if there is any connection request for WiFi network.
8305     * Note, caller of this helper function must acquire mWifiReqCountLock.
8306     */
8307    private boolean hasConnectionRequests() {
8308        return mConnectionReqCount > 0 || mUntrustedReqCount > 0;
8309    }
8310}
8311