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