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