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