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