WifiStateMachine.java revision f11073c03746f1c79e6a316884bc59574b562a8b
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                        int alertReason = message.arg1;
3934                        mWifiDiagnostics.captureAlertData(alertReason, buffer);
3935                        mWifiMetrics.incrementAlertReasonCount(alertReason);
3936                    }
3937                    break;
3938                case CMD_GET_LINK_LAYER_STATS:
3939                    // Not supported hence reply with error message
3940                    replyToMessage(message, message.what, null);
3941                    break;
3942                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
3943                    NetworkInfo info = (NetworkInfo) message.obj;
3944                    mP2pConnected.set(info.isConnected());
3945                    break;
3946                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
3947                    mTemporarilyDisconnectWifi = (message.arg1 == 1);
3948                    replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
3949                    break;
3950                /* Link configuration (IP address, DNS, ...) changes notified via netlink */
3951                case CMD_UPDATE_LINKPROPERTIES:
3952                    updateLinkProperties((LinkProperties) message.obj);
3953                    break;
3954                case CMD_GET_MATCHING_CONFIG:
3955                    replyToMessage(message, message.what);
3956                    break;
3957                case CMD_IP_CONFIGURATION_SUCCESSFUL:
3958                case CMD_IP_CONFIGURATION_LOST:
3959                case CMD_IP_REACHABILITY_LOST:
3960                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3961                    break;
3962                case CMD_GET_CONNECTION_STATISTICS:
3963                    replyToMessage(message, message.what, mWifiConnectionStatistics);
3964                    break;
3965                case CMD_REMOVE_APP_CONFIGURATIONS:
3966                    deferMessage(message);
3967                    break;
3968                case CMD_REMOVE_USER_CONFIGURATIONS:
3969                    deferMessage(message);
3970                    break;
3971                case CMD_START_IP_PACKET_OFFLOAD:
3972                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
3973                            message.arg1,
3974                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
3975                    break;
3976                case CMD_STOP_IP_PACKET_OFFLOAD:
3977                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
3978                            message.arg1,
3979                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
3980                    break;
3981                case CMD_START_RSSI_MONITORING_OFFLOAD:
3982                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3983                    break;
3984                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
3985                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3986                    break;
3987                case CMD_USER_SWITCH:
3988                    mWifiConfigManager.handleUserSwitch(message.arg1);
3989                    break;
3990                case CMD_ADD_PASSPOINT_MO:
3991                case CMD_MODIFY_PASSPOINT_MO:
3992                case CMD_QUERY_OSU_ICON:
3993                case CMD_MATCH_PROVIDER_NETWORK:
3994                    /* reply with arg1 = 0 - it returns API failure to the calling app
3995                     * (message.what is not looked at)
3996                     */
3997                    replyToMessage(message, message.what);
3998                    break;
3999                case CMD_RESET_SIM_NETWORKS:
4000                    /* Defer this message until supplicant is started. */
4001                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4002                    deferMessage(message);
4003                    break;
4004                case CMD_INSTALL_PACKET_FILTER:
4005                    mWifiNative.installPacketFilter((byte[]) message.obj);
4006                    break;
4007                case CMD_SET_FALLBACK_PACKET_FILTERING:
4008                    if ((boolean) message.obj) {
4009                        mWifiNative.startFilteringMulticastV4Packets();
4010                    } else {
4011                        mWifiNative.stopFilteringMulticastV4Packets();
4012                    }
4013                    break;
4014                case CMD_CLIENT_INTERFACE_BINDER_DEATH:
4015                    // We have lost contact with a client interface, which means that we cannot
4016                    // trust that the driver is up or that the interface is ready.  We are fit
4017                    // for no WiFi related work.
4018                    transitionTo(mInitialState);
4019                    break;
4020                default:
4021                    loge("Error! unhandled message" + message);
4022                    break;
4023            }
4024            return HANDLED;
4025        }
4026    }
4027
4028    class InitialState extends State {
4029
4030        private void cleanup() {
4031            // Tearing down the client interfaces below is going to stop our supplicant.
4032            mWifiMonitor.stopAllMonitoring();
4033
4034            mDeathRecipient.unlinkToDeath();
4035            if (mWificond != null) {
4036                try {
4037                    mWificond.tearDownInterfaces();
4038                } catch (RemoteException e) {
4039                    // There is very little we can do here
4040                    Log.e(TAG, "Failed to tear down interfaces via wificond");
4041                }
4042                mWificond = null;
4043            }
4044            mWifiNative.stopHal();
4045        }
4046
4047        @Override
4048        public void enter() {
4049            cleanup();
4050            if (mWifiP2pChannel == null && mWifiP2pServiceImpl != null) {
4051                mWifiP2pChannel = new AsyncChannel();
4052                mWifiP2pChannel.connect(mContext, getHandler(),
4053                    mWifiP2pServiceImpl.getP2pStateMachineMessenger());
4054            }
4055
4056            if (mWifiApConfigStore == null) {
4057                mWifiApConfigStore =
4058                        mFacade.makeApConfigStore(mContext, mBackupManagerProxy);
4059            }
4060        }
4061        @Override
4062        public boolean processMessage(Message message) {
4063            logStateAndMessage(message, this);
4064            switch (message.what) {
4065                case CMD_START_SUPPLICANT:
4066                    // Refresh our reference to wificond.  This allows us to tolerate restarts.
4067                    mWificond = mWifiInjector.makeWificond();
4068                    mClientInterface = setupDriverForClientMode(mWificond);
4069                    if (mClientInterface == null ||
4070                            !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {
4071                        setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
4072                        cleanup();
4073                        break;
4074                    }
4075
4076                    try {
4077                        // A runtime crash can leave the interface up and
4078                        // IP addresses configured, and this affects
4079                        // connectivity when supplicant starts up.
4080                        // Ensure interface is down and we have no IP
4081                        // addresses before a supplicant start.
4082                        mNwService.setInterfaceDown(mInterfaceName);
4083                        mNwService.clearInterfaceAddresses(mInterfaceName);
4084
4085                        // Set privacy extensions
4086                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
4087
4088                        // IPv6 is enabled only as long as access point is connected since:
4089                        // - IPv6 addresses and routes stick around after disconnection
4090                        // - kernel is unaware when connected and fails to start IPv6 negotiation
4091                        // - kernel can start autoconfiguration when 802.1x is not complete
4092                        mNwService.disableIpv6(mInterfaceName);
4093                    } catch (RemoteException re) {
4094                        loge("Unable to change interface settings: " + re);
4095                    } catch (IllegalStateException ie) {
4096                        loge("Unable to change interface settings: " + ie);
4097                    }
4098
4099                    if (!mWifiNative.startHal()) {
4100                        // starting HAL is optional
4101                        Log.e(TAG, "Failed to start HAL for client mode");
4102                    }
4103
4104                    try {
4105                        if (!mClientInterface.enableSupplicant()) {
4106                            loge("Failed to start supplicant!");
4107                            setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
4108                            cleanup();
4109                            break;
4110                        }
4111                    } catch (RemoteException e) {
4112                        cleanup();
4113                        break;
4114                    }
4115                    setSupplicantLogLevel();
4116                    setWifiState(WIFI_STATE_ENABLING);
4117                    if (mVerboseLoggingEnabled) log("Supplicant start successful");
4118                    mWifiMonitor.startMonitoring(mInterfaceName);
4119                    transitionTo(mSupplicantStartingState);
4120                    break;
4121                case CMD_START_AP:
4122                    // Refresh our reference to wificond.  This allows us to tolerate restarts.
4123                    mWificond = mWifiInjector.makeWificond();
4124                    transitionTo(mSoftApState);
4125                    break;
4126                case CMD_SET_OPERATIONAL_MODE:
4127                    mOperationalMode = message.arg1;
4128                    if (mOperationalMode != DISABLED_MODE) {
4129                        sendMessage(CMD_START_SUPPLICANT);
4130                    }
4131                    break;
4132                default:
4133                    return NOT_HANDLED;
4134            }
4135            return HANDLED;
4136        }
4137    }
4138
4139    class SupplicantStartingState extends State {
4140        private void initializeWpsDetails() {
4141            String detail;
4142            detail = mPropertyService.get("ro.product.name", "");
4143            if (!mWifiNative.setDeviceName(detail)) {
4144                loge("Failed to set device name " +  detail);
4145            }
4146            detail = mPropertyService.get("ro.product.manufacturer", "");
4147            if (!mWifiNative.setManufacturer(detail)) {
4148                loge("Failed to set manufacturer " + detail);
4149            }
4150            detail = mPropertyService.get("ro.product.model", "");
4151            if (!mWifiNative.setModelName(detail)) {
4152                loge("Failed to set model name " + detail);
4153            }
4154            detail = mPropertyService.get("ro.product.model", "");
4155            if (!mWifiNative.setModelNumber(detail)) {
4156                loge("Failed to set model number " + detail);
4157            }
4158            detail = mPropertyService.get("ro.serialno", "");
4159            if (!mWifiNative.setSerialNumber(detail)) {
4160                loge("Failed to set serial number " + detail);
4161            }
4162            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
4163                loge("Failed to set WPS config methods");
4164            }
4165            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
4166                loge("Failed to set primary device type " + mPrimaryDeviceType);
4167            }
4168        }
4169
4170        @Override
4171        public boolean processMessage(Message message) {
4172            logStateAndMessage(message, this);
4173
4174            switch(message.what) {
4175                case WifiMonitor.SUP_CONNECTION_EVENT:
4176                    if (mVerboseLoggingEnabled) log("Supplicant connection established");
4177                    setWifiState(WIFI_STATE_ENABLED);
4178                    mSupplicantRestartCount = 0;
4179                    /* Reset the supplicant state to indicate the supplicant
4180                     * state is not known at this time */
4181                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4182                    /* Initialize data structures */
4183                    mLastBssid = null;
4184                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4185                    mLastSignalLevel = -1;
4186
4187                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
4188                    /* set frequency band of operation */
4189                    setFrequencyBand();
4190                    mWifiNative.enableSaveConfig();
4191                    mWifiConfigManager.loadAndEnableAllNetworks();
4192                    initializeWpsDetails();
4193
4194                    sendSupplicantConnectionChangedBroadcast(true);
4195                    transitionTo(mSupplicantStartedState);
4196                    break;
4197                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4198                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
4199                        loge("Failed to setup control channel, restart supplicant");
4200                        mWifiMonitor.stopAllMonitoring();
4201                        try {
4202                            mClientInterface.disableSupplicant();
4203                        } catch (RemoteException e) {
4204                            // The client interface is dead, there is nothing more we can do.
4205                        }
4206                        transitionTo(mInitialState);
4207                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4208                    } else {
4209                        loge("Failed " + mSupplicantRestartCount +
4210                                " times to start supplicant, unload driver");
4211                        mSupplicantRestartCount = 0;
4212                        setWifiState(WIFI_STATE_UNKNOWN);
4213                        transitionTo(mInitialState);
4214                    }
4215                    break;
4216                case CMD_START_SUPPLICANT:
4217                case CMD_STOP_SUPPLICANT:
4218                case CMD_START_AP:
4219                case CMD_STOP_AP:
4220                case CMD_SET_OPERATIONAL_MODE:
4221                case CMD_SET_FREQUENCY_BAND:
4222                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4223                    deferMessage(message);
4224                    break;
4225                default:
4226                    return NOT_HANDLED;
4227            }
4228            return HANDLED;
4229        }
4230    }
4231
4232    class SupplicantStartedState extends State {
4233        @Override
4234        public void enter() {
4235            if (mVerboseLoggingEnabled) {
4236                logd("SupplicantStartedState enter");
4237            }
4238
4239            /* Wifi is available as long as we have a connection to supplicant */
4240            mNetworkInfo.setIsAvailable(true);
4241            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4242
4243            int defaultInterval = mContext.getResources().getInteger(
4244                    R.integer.config_wifi_supplicant_scan_interval);
4245
4246            mSupplicantScanIntervalMs = mFacade.getLongSetting(mContext,
4247                    Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
4248                    defaultInterval);
4249
4250            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
4251            mWifiNative.setExternalSim(true);
4252
4253            /* turn on use of DFS channels */
4254            mWifiNative.setDfsFlag(true);
4255
4256            setRandomMacOui();
4257            mWifiNative.enableAutoConnect(false);
4258            mCountryCode.setReadyForChange(true);
4259
4260            // We can't do this in the constructor because WifiStateMachine is created before the
4261            // wifi scanning service is initialized
4262            if (mWifiScanner == null) {
4263                mWifiScanner = mFacade.makeWifiScanner(mContext, getHandler().getLooper());
4264
4265                mWifiConnectivityManager = new WifiConnectivityManager(mContext,
4266                    WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo,
4267                    mWifiQualifiedNetworkSelector, mWifiInjector,
4268                    getHandler().getLooper());
4269            }
4270
4271            mWifiDiagnostics.startLogging(mVerboseLoggingEnabled);
4272            mIsRunning = true;
4273            updateBatteryWorkSource(null);
4274            /**
4275             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
4276             * When this mode is on, some of the low-level scan parameters used by the
4277             * driver are changed to reduce interference with bluetooth
4278             */
4279            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4280            /* initialize network state */
4281            setNetworkDetailedState(DetailedState.DISCONNECTED);
4282
4283            // Disable legacy multicast filtering, which on some chipsets defaults to enabled.
4284            // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
4285            // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
4286            // IpManager.Callback.setFallbackMulticastFilter()
4287            mWifiNative.stopFilteringMulticastV4Packets();
4288            mWifiNative.stopFilteringMulticastV6Packets();
4289
4290            if (mOperationalMode == SCAN_ONLY_MODE ||
4291                    mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4292                mWifiNative.disconnect();
4293                mWifiConfigManager.disableAllNetworksNative();
4294                if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4295                    setWifiState(WIFI_STATE_DISABLED);
4296                }
4297                transitionTo(mScanModeState);
4298            } else if (mOperationalMode == CONNECT_MODE){
4299
4300                // Status pulls in the current supplicant state and network connection state
4301                // events over the monitor connection. This helps framework sync up with
4302                // current supplicant state
4303                // TODO: actually check the supplicant status string and make sure the supplicant
4304                // is in disconnecte4d state.
4305                mWifiNative.status();
4306                // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
4307                transitionTo(mDisconnectedState);
4308            } else if (mOperationalMode == DISABLED_MODE) {
4309                transitionTo(mSupplicantStoppingState);
4310            }
4311
4312            // We may have missed screen update at boot
4313            if (mScreenBroadcastReceived.get() == false) {
4314                PowerManager powerManager = (PowerManager)mContext.getSystemService(
4315                        Context.POWER_SERVICE);
4316                handleScreenStateChanged(powerManager.isInteractive());
4317            } else {
4318                // Set the right suspend mode settings
4319                mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
4320                        && mUserWantsSuspendOpt.get());
4321
4322                // Inform WifiConnectivtyManager the screen state in case
4323                // WifiConnectivityManager missed the last screen update because
4324                // it was not started yet.
4325                mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);
4326            }
4327            mWifiNative.setPowerSave(true);
4328
4329            if (mP2pSupported) {
4330                if (mOperationalMode == CONNECT_MODE) {
4331                    p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
4332                } else {
4333                    // P2P state machine starts in disabled state, and is not enabled until
4334                    // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
4335                    // keep it disabled.
4336                }
4337            }
4338
4339            if (mNanSupported && mWifiNanManager != null) {
4340                if (mOperationalMode == CONNECT_MODE) {
4341                    mWifiNanManager.enableUsage();
4342                } else {
4343                    /*
4344                     * NAN state machine starts in disabled state. Nothing
4345                     * needed to keep it disabled.
4346                     */
4347                }
4348            }
4349
4350            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4351            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4352            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
4353            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4354
4355            // Enable link layer stats gathering
4356            mWifiNative.setWifiLinkLayerStats("wlan0", 1);
4357        }
4358
4359        @Override
4360        public boolean processMessage(Message message) {
4361            logStateAndMessage(message, this);
4362
4363            switch(message.what) {
4364                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
4365                    if (mP2pSupported) {
4366                        transitionTo(mWaitForP2pDisableState);
4367                    } else {
4368                        transitionTo(mSupplicantStoppingState);
4369                    }
4370                    break;
4371                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
4372                    loge("Connection lost, restart supplicant");
4373                    handleSupplicantConnectionLoss(true);
4374                    handleNetworkDisconnect();
4375                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4376                    if (mP2pSupported) {
4377                        transitionTo(mWaitForP2pDisableState);
4378                    } else {
4379                        transitionTo(mInitialState);
4380                    }
4381                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4382                    break;
4383                case CMD_START_SCAN:
4384                    handleScanRequest(message);
4385                    break;
4386                case WifiMonitor.SCAN_RESULTS_EVENT:
4387                case WifiMonitor.SCAN_FAILED_EVENT:
4388                    maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
4389                    setScanResults();
4390                    if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
4391                        /* Just updated results from full scan, let apps know about this */
4392                        boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
4393                        sendScanResultsAvailableBroadcast(scanSucceeded);
4394                    }
4395                    mSendScanResultsBroadcast = false;
4396                    mIsScanOngoing = false;
4397                    mIsFullScanOngoing = false;
4398                    if (mBufferedScanMsg.size() > 0)
4399                        sendMessage(mBufferedScanMsg.remove());
4400                    break;
4401                case CMD_PING_SUPPLICANT:
4402                    boolean ok = mWifiNative.ping();
4403                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
4404                    break;
4405                case CMD_SET_FREQUENCY_BAND:
4406                    int band =  message.arg1;
4407                    if (mVerboseLoggingEnabled) log("set frequency band " + band);
4408                    if (mWifiNative.setBand(band)) {
4409
4410                        if (mVerboseLoggingEnabled)  logd("did set frequency band " + band);
4411
4412                        mFrequencyBand.set(band);
4413                        // Flush old data - like scan results
4414                        mWifiNative.bssFlush();
4415
4416                        if (mVerboseLoggingEnabled)  logd("done set frequency band " + band);
4417
4418                    } else {
4419                        loge("Failed to set frequency band " + band);
4420                    }
4421                    break;
4422                case CMD_GET_CAPABILITY_FREQ:
4423                    String freqs = mWifiNative.getFreqCapability();
4424                    replyToMessage(message, message.what, freqs);
4425                    break;
4426                case CMD_START_AP:
4427                    /* Cannot start soft AP while in client mode */
4428                    loge("Failed to start soft AP with a running supplicant");
4429                    setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
4430                    break;
4431                case CMD_SET_OPERATIONAL_MODE:
4432                    mOperationalMode = message.arg1;
4433                    mWifiConfigManager.
4434                            setAndEnableLastSelectedConfiguration(
4435                                    WifiConfiguration.INVALID_NETWORK_ID);
4436                    if (mOperationalMode == DISABLED_MODE) {
4437                        transitionTo(mSupplicantStoppingState);
4438                    }
4439                    break;
4440                case CMD_TARGET_BSSID:
4441                    // Trying to associate to this BSSID
4442                    if (message.obj != null) {
4443                        mTargetRoamBSSID = (String) message.obj;
4444                    }
4445                    break;
4446                case CMD_GET_LINK_LAYER_STATS:
4447                    WifiLinkLayerStats stats = getWifiLinkLayerStats();
4448                    replyToMessage(message, message.what, stats);
4449                    break;
4450                case CMD_RESET_SIM_NETWORKS:
4451                    log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
4452                    mWifiConfigManager.resetSimNetworks();
4453                    break;
4454                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
4455                    mBluetoothConnectionActive = (message.arg1 !=
4456                            BluetoothAdapter.STATE_DISCONNECTED);
4457                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4458                    break;
4459                case CMD_SET_SUSPEND_OPT_ENABLED:
4460                    if (message.arg1 == 1) {
4461                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
4462                        if (message.arg2 == 1) {
4463                            mSuspendWakeLock.release();
4464                        }
4465                    } else {
4466                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
4467                    }
4468                    break;
4469                case CMD_SET_HIGH_PERF_MODE:
4470                    if (message.arg1 == 1) {
4471                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
4472                    } else {
4473                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
4474                    }
4475                    break;
4476                case CMD_ENABLE_TDLS:
4477                    if (message.obj != null) {
4478                        String remoteAddress = (String) message.obj;
4479                        boolean enable = (message.arg1 == 1);
4480                        mWifiNative.startTdls(remoteAddress, enable);
4481                    }
4482                    break;
4483                case WifiMonitor.ANQP_DONE_EVENT:
4484                    mWifiConfigManager.notifyANQPDone((Long) message.obj, message.arg1 != 0);
4485                    break;
4486                case CMD_STOP_IP_PACKET_OFFLOAD: {
4487                    int slot = message.arg1;
4488                    int ret = stopWifiIPPacketOffload(slot);
4489                    if (mNetworkAgent != null) {
4490                        mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
4491                    }
4492                    break;
4493                }
4494                case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4495                    mWifiConfigManager.notifyIconReceived((IconEvent) message.obj);
4496                    break;
4497                case WifiMonitor.HS20_REMEDIATION_EVENT:
4498                    wnmFrameReceived((WnmData) message.obj);
4499                    break;
4500                case CMD_CONFIG_ND_OFFLOAD:
4501                    final boolean enabled = (message.arg1 > 0);
4502                    mWifiNative.configureNeighborDiscoveryOffload(enabled);
4503                    break;
4504                case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
4505                    if (mWifiConnectivityManager != null) {
4506                        mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
4507                    }
4508                    break;
4509                case CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED:
4510                    final boolean allowed = (message.arg1 > 0);
4511                    boolean old_state = mWifiConfigManager.getEnableAutoJoinWhenAssociated();
4512                    mWifiConfigManager.setEnableAutoJoinWhenAssociated(allowed);
4513                    if (!old_state && allowed && mScreenOn
4514                            && getCurrentState() == mConnectedState) {
4515                        if (mWifiConnectivityManager != null) {
4516                            mWifiConnectivityManager.forceConnectivityScan();
4517                        }
4518                    }
4519                    break;
4520                default:
4521                    return NOT_HANDLED;
4522            }
4523            return HANDLED;
4524        }
4525
4526        @Override
4527        public void exit() {
4528            mWifiDiagnostics.stopLogging();
4529
4530            mIsRunning = false;
4531            updateBatteryWorkSource(null);
4532            mScanResults = new ArrayList<>();
4533
4534            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4535            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4536            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
4537            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4538            mBufferedScanMsg.clear();
4539
4540            if (mNanSupported && mWifiNanManager != null) {
4541                mWifiNanManager.disableUsage();
4542            }
4543
4544            mNetworkInfo.setIsAvailable(false);
4545            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4546            mCountryCode.setReadyForChange(false);
4547        }
4548    }
4549
4550    class SupplicantStoppingState extends State {
4551        @Override
4552        public void enter() {
4553            /* Send any reset commands to supplicant before shutting it down */
4554            handleNetworkDisconnect();
4555
4556            String suppState = System.getProperty("init.svc.wpa_supplicant");
4557            if (suppState == null) suppState = "unknown";
4558
4559            logd("SupplicantStoppingState: stopSupplicant "
4560                    + " init.svc.wpa_supplicant=" + suppState);
4561            mWifiMonitor.stopSupplicant();
4562
4563            /* Send ourselves a delayed message to indicate failure after a wait time */
4564            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
4565                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
4566            setWifiState(WIFI_STATE_DISABLING);
4567            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4568        }
4569        @Override
4570        public boolean processMessage(Message message) {
4571            logStateAndMessage(message, this);
4572
4573            switch(message.what) {
4574                case WifiMonitor.SUP_CONNECTION_EVENT:
4575                    loge("Supplicant connection received while stopping");
4576                    break;
4577                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4578                    if (mVerboseLoggingEnabled) log("Supplicant connection lost");
4579                    handleSupplicantConnectionLoss(false);
4580                    transitionTo(mInitialState);
4581                    break;
4582                case CMD_STOP_SUPPLICANT_FAILED:
4583                    if (message.arg1 == mSupplicantStopFailureToken) {
4584                        loge("Timed out on a supplicant stop, kill and proceed");
4585                        handleSupplicantConnectionLoss(true);
4586                        transitionTo(mInitialState);
4587                    }
4588                    break;
4589                case CMD_START_SUPPLICANT:
4590                case CMD_STOP_SUPPLICANT:
4591                case CMD_START_AP:
4592                case CMD_STOP_AP:
4593                case CMD_SET_OPERATIONAL_MODE:
4594                case CMD_SET_FREQUENCY_BAND:
4595                    deferMessage(message);
4596                    break;
4597                default:
4598                    return NOT_HANDLED;
4599            }
4600            return HANDLED;
4601        }
4602    }
4603
4604    class WaitForP2pDisableState extends State {
4605        private State mTransitionToState;
4606        @Override
4607        public void enter() {
4608            switch (getCurrentMessage().what) {
4609                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4610                    mTransitionToState = mInitialState;
4611                    break;
4612                case CMD_STOP_SUPPLICANT:
4613                default:
4614                    mTransitionToState = mSupplicantStoppingState;
4615                    break;
4616            }
4617            p2pSendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
4618        }
4619        @Override
4620        public boolean processMessage(Message message) {
4621            logStateAndMessage(message, this);
4622
4623            switch(message.what) {
4624                case WifiStateMachine.CMD_DISABLE_P2P_RSP:
4625                    transitionTo(mTransitionToState);
4626                    break;
4627                /* Defer wifi start/shut and driver commands */
4628                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4629                case CMD_START_SUPPLICANT:
4630                case CMD_STOP_SUPPLICANT:
4631                case CMD_START_AP:
4632                case CMD_STOP_AP:
4633                case CMD_SET_OPERATIONAL_MODE:
4634                case CMD_SET_FREQUENCY_BAND:
4635                case CMD_START_SCAN:
4636                case CMD_DISCONNECT:
4637                case CMD_REASSOCIATE:
4638                case CMD_RECONNECT:
4639                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4640                    deferMessage(message);
4641                    break;
4642                default:
4643                    return NOT_HANDLED;
4644            }
4645            return HANDLED;
4646        }
4647    }
4648
4649    class ScanModeState extends State {
4650        private int mLastOperationMode;
4651        @Override
4652        public void enter() {
4653            mLastOperationMode = mOperationalMode;
4654        }
4655        @Override
4656        public boolean processMessage(Message message) {
4657            logStateAndMessage(message, this);
4658
4659            switch(message.what) {
4660                case CMD_SET_OPERATIONAL_MODE:
4661                    if (message.arg1 == CONNECT_MODE) {
4662
4663                        if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4664                            setWifiState(WIFI_STATE_ENABLED);
4665                            // Load and re-enable networks when going back to enabled state
4666                            // This is essential for networks to show up after restore
4667                            mWifiConfigManager.loadAndEnableAllNetworks();
4668                            p2pSendMessage(CMD_ENABLE_P2P);
4669                        } else {
4670                            mWifiConfigManager.enableAllNetworks();
4671                        }
4672
4673                        // Lose last selection choice since user toggled WiFi
4674                        mWifiConfigManager.
4675                                setAndEnableLastSelectedConfiguration(
4676                                        WifiConfiguration.INVALID_NETWORK_ID);
4677
4678                        mOperationalMode = CONNECT_MODE;
4679                        transitionTo(mDisconnectedState);
4680                    } else if (message.arg1 == DISABLED_MODE) {
4681                        transitionTo(mSupplicantStoppingState);
4682                    }
4683                    // Nothing to do
4684                    break;
4685                // Handle scan. All the connection related commands are
4686                // handled only in ConnectModeState
4687                case CMD_START_SCAN:
4688                    handleScanRequest(message);
4689                    break;
4690                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4691                    SupplicantState state = handleSupplicantStateChange(message);
4692                    if (mVerboseLoggingEnabled) log("SupplicantState= " + state);
4693                    break;
4694                default:
4695                    return NOT_HANDLED;
4696            }
4697            return HANDLED;
4698        }
4699    }
4700
4701
4702    String smToString(Message message) {
4703        return smToString(message.what);
4704    }
4705
4706    String smToString(int what) {
4707        String s = sSmToString.get(what);
4708        if (s != null) {
4709            return s;
4710        }
4711        switch (what) {
4712            case WifiMonitor.DRIVER_HUNG_EVENT:
4713                s = "DRIVER_HUNG_EVENT";
4714                break;
4715            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
4716                s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
4717                break;
4718            case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
4719                s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
4720                break;
4721            case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4722                s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
4723                break;
4724            case WifiManager.DISABLE_NETWORK:
4725                s = "WifiManager.DISABLE_NETWORK";
4726                break;
4727            case WifiManager.CONNECT_NETWORK:
4728                s = "CONNECT_NETWORK";
4729                break;
4730            case WifiManager.SAVE_NETWORK:
4731                s = "SAVE_NETWORK";
4732                break;
4733            case WifiManager.FORGET_NETWORK:
4734                s = "FORGET_NETWORK";
4735                break;
4736            case WifiMonitor.SUP_CONNECTION_EVENT:
4737                s = "SUP_CONNECTION_EVENT";
4738                break;
4739            case WifiMonitor.SUP_DISCONNECTION_EVENT:
4740                s = "SUP_DISCONNECTION_EVENT";
4741                break;
4742            case WifiMonitor.SCAN_RESULTS_EVENT:
4743                s = "SCAN_RESULTS_EVENT";
4744                break;
4745            case WifiMonitor.SCAN_FAILED_EVENT:
4746                s = "SCAN_FAILED_EVENT";
4747                break;
4748            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4749                s = "SUPPLICANT_STATE_CHANGE_EVENT";
4750                break;
4751            case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4752                s = "AUTHENTICATION_FAILURE_EVENT";
4753                break;
4754            case WifiMonitor.SSID_TEMP_DISABLED:
4755                s = "SSID_TEMP_DISABLED";
4756                break;
4757            case WifiMonitor.SSID_REENABLED:
4758                s = "SSID_REENABLED";
4759                break;
4760            case WifiMonitor.WPS_SUCCESS_EVENT:
4761                s = "WPS_SUCCESS_EVENT";
4762                break;
4763            case WifiMonitor.WPS_FAIL_EVENT:
4764                s = "WPS_FAIL_EVENT";
4765                break;
4766            case WifiMonitor.SUP_REQUEST_IDENTITY:
4767                s = "SUP_REQUEST_IDENTITY";
4768                break;
4769            case WifiMonitor.NETWORK_CONNECTION_EVENT:
4770                s = "NETWORK_CONNECTION_EVENT";
4771                break;
4772            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4773                s = "NETWORK_DISCONNECTION_EVENT";
4774                break;
4775            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4776                s = "ASSOCIATION_REJECTION_EVENT";
4777                break;
4778            case WifiMonitor.ANQP_DONE_EVENT:
4779                s = "WifiMonitor.ANQP_DONE_EVENT";
4780                break;
4781            case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4782                s = "WifiMonitor.RX_HS20_ANQP_ICON_EVENT";
4783                break;
4784            case WifiMonitor.GAS_QUERY_DONE_EVENT:
4785                s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
4786                break;
4787            case WifiMonitor.HS20_REMEDIATION_EVENT:
4788                s = "WifiMonitor.HS20_REMEDIATION_EVENT";
4789                break;
4790            case WifiMonitor.GAS_QUERY_START_EVENT:
4791                s = "WifiMonitor.GAS_QUERY_START_EVENT";
4792                break;
4793            case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
4794                s = "GROUP_CREATING_TIMED_OUT";
4795                break;
4796            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
4797                s = "P2P_CONNECTION_CHANGED";
4798                break;
4799            case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
4800                s = "P2P.DISCONNECT_WIFI_RESPONSE";
4801                break;
4802            case WifiP2pServiceImpl.SET_MIRACAST_MODE:
4803                s = "P2P.SET_MIRACAST_MODE";
4804                break;
4805            case WifiP2pServiceImpl.BLOCK_DISCOVERY:
4806                s = "P2P.BLOCK_DISCOVERY";
4807                break;
4808            case WifiManager.CANCEL_WPS:
4809                s = "CANCEL_WPS";
4810                break;
4811            case WifiManager.CANCEL_WPS_FAILED:
4812                s = "CANCEL_WPS_FAILED";
4813                break;
4814            case WifiManager.CANCEL_WPS_SUCCEDED:
4815                s = "CANCEL_WPS_SUCCEDED";
4816                break;
4817            case WifiManager.START_WPS:
4818                s = "START_WPS";
4819                break;
4820            case WifiManager.START_WPS_SUCCEEDED:
4821                s = "START_WPS_SUCCEEDED";
4822                break;
4823            case WifiManager.WPS_FAILED:
4824                s = "WPS_FAILED";
4825                break;
4826            case WifiManager.WPS_COMPLETED:
4827                s = "WPS_COMPLETED";
4828                break;
4829            case WifiManager.RSSI_PKTCNT_FETCH:
4830                s = "RSSI_PKTCNT_FETCH";
4831                break;
4832            default:
4833                s = "what:" + Integer.toString(what);
4834                break;
4835        }
4836        return s;
4837    }
4838
4839    void registerConnected() {
4840        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4841            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
4842            if (config != null) {
4843                //Here we will clear all disable counters once a network is connected
4844                //records how long this network is connected in future
4845                config.lastConnected = mClock.getWallClockMillis();
4846                config.numAssociation++;
4847                WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
4848                        config.getNetworkSelectionStatus();
4849                networkSelectionStatus.clearDisableReasonCounter();
4850                networkSelectionStatus.setHasEverConnected(true);
4851            }
4852            // On connect, reset wifiScoreReport
4853            mWifiScoreReport = null;
4854       }
4855    }
4856
4857    void registerDisconnected() {
4858        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4859            // We are switching away from this configuration,
4860            // hence record the time we were connected last
4861            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
4862            if (config != null) {
4863                config.lastDisconnected = mClock.getWallClockMillis();
4864                if (config.ephemeral) {
4865                    // Remove ephemeral WifiConfigurations from file
4866                    mWifiConfigManager.forgetNetwork(mLastNetworkId);
4867                }
4868            }
4869        }
4870    }
4871
4872    void noteWifiDisabledWhileAssociated() {
4873        // We got disabled by user while we were associated, make note of it
4874        int rssi = mWifiInfo.getRssi();
4875        WifiConfiguration config = getCurrentWifiConfiguration();
4876        if (getCurrentState() == mConnectedState
4877                && rssi != WifiInfo.INVALID_RSSI
4878                && config != null) {
4879            boolean is24GHz = mWifiInfo.is24GHz();
4880            boolean isBadRSSI = (is24GHz && rssi < mWifiConfigManager.mThresholdMinimumRssi24.get())
4881                    || (!is24GHz && rssi < mWifiConfigManager.mThresholdMinimumRssi5.get());
4882            boolean isLowRSSI =
4883                    (is24GHz && rssi < mWifiConfigManager.mThresholdQualifiedRssi24.get())
4884                            || (!is24GHz && mWifiInfo.getRssi() <
4885                                    mWifiConfigManager.mThresholdQualifiedRssi5.get());
4886            boolean isHighRSSI = (is24GHz && rssi
4887                    >= mWifiConfigManager.mThresholdSaturatedRssi24.get())
4888                    || (!is24GHz && mWifiInfo.getRssi()
4889                    >= mWifiConfigManager.mThresholdSaturatedRssi5.get());
4890            if (isBadRSSI) {
4891                // Take note that we got disabled while RSSI was Bad
4892                config.numUserTriggeredWifiDisableLowRSSI++;
4893            } else if (isLowRSSI) {
4894                // Take note that we got disabled while RSSI was Low
4895                config.numUserTriggeredWifiDisableBadRSSI++;
4896            } else if (!isHighRSSI) {
4897                // Take note that we got disabled while RSSI was Not high
4898                config.numUserTriggeredWifiDisableNotHighRSSI++;
4899            }
4900        }
4901    }
4902
4903    /**
4904     * Returns Wificonfiguration object correponding to the currently connected network, null if
4905     * not connected.
4906     */
4907    public WifiConfiguration getCurrentWifiConfiguration() {
4908        if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
4909            return null;
4910        }
4911        return mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
4912    }
4913
4914    ScanResult getCurrentScanResult() {
4915        WifiConfiguration config = getCurrentWifiConfiguration();
4916        if (config == null) {
4917            return null;
4918        }
4919        String BSSID = mWifiInfo.getBSSID();
4920        if (BSSID == null) {
4921            BSSID = mTargetRoamBSSID;
4922        }
4923        ScanDetailCache scanDetailCache =
4924                mWifiConfigManager.getScanDetailCache(config);
4925
4926        if (scanDetailCache == null) {
4927            return null;
4928        }
4929
4930        return scanDetailCache.get(BSSID);
4931    }
4932
4933    String getCurrentBSSID() {
4934        if (isLinkDebouncing()) {
4935            return null;
4936        }
4937        return mLastBssid;
4938    }
4939
4940    class ConnectModeState extends State {
4941
4942        @Override
4943        public void enter() {
4944            // Inform WifiConnectivityManager that Wifi is enabled
4945            if (mWifiConnectivityManager != null) {
4946                mWifiConnectivityManager.setWifiEnabled(true);
4947            }
4948            // Inform metrics that Wifi is Enabled (but not yet connected)
4949            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
4950        }
4951
4952        @Override
4953        public void exit() {
4954            // Inform WifiConnectivityManager that Wifi is disabled
4955            if (mWifiConnectivityManager != null) {
4956                mWifiConnectivityManager.setWifiEnabled(false);
4957            }
4958            // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
4959            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
4960        }
4961
4962        @Override
4963        public boolean processMessage(Message message) {
4964            WifiConfiguration config;
4965            int netId;
4966            boolean ok;
4967            boolean didDisconnect;
4968            String bssid;
4969            String ssid;
4970            NetworkUpdateResult result;
4971            logStateAndMessage(message, this);
4972
4973            switch (message.what) {
4974                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4975                    mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
4976                    didBlackListBSSID = false;
4977                    bssid = (String) message.obj;
4978                    if (bssid == null || TextUtils.isEmpty(bssid)) {
4979                        // If BSSID is null, use the target roam BSSID
4980                        bssid = mTargetRoamBSSID;
4981                    }
4982                    if (bssid != null) {
4983                        // If we have a BSSID, tell configStore to black list it
4984                        if (mWifiConnectivityManager != null) {
4985                            didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid,
4986                                    false);
4987                        }
4988                    }
4989
4990                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
4991                            WifiConfiguration.NetworkSelectionStatus
4992                            .DISABLED_ASSOCIATION_REJECTION);
4993
4994                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
4995                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
4996                    reportConnectionAttemptEnd(
4997                            WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
4998                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
4999                    mWifiInjector.getWifiLastResortWatchdog()
5000                            .noteConnectionFailureAndTriggerIfNeeded(
5001                                    getTargetSsid(), bssid,
5002                                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
5003                    break;
5004                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5005                    mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
5006                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
5007                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5008                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
5009                                WifiConfiguration.NetworkSelectionStatus
5010                                        .DISABLED_AUTHENTICATION_FAILURE);
5011                    }
5012                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
5013                    reportConnectionAttemptEnd(
5014                            WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
5015                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5016                    mWifiInjector.getWifiLastResortWatchdog()
5017                            .noteConnectionFailureAndTriggerIfNeeded(
5018                                    getTargetSsid(), mTargetRoamBSSID,
5019                                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
5020                    break;
5021                case WifiMonitor.SSID_TEMP_DISABLED:
5022                    Log.e(TAG, "Supplicant SSID temporary disabled:"
5023                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5024                    mWifiConfigManager.updateNetworkSelectionStatus(
5025                            message.arg1,
5026                            WifiConfiguration.NetworkSelectionStatus
5027                            .DISABLED_AUTHENTICATION_FAILURE);
5028                    reportConnectionAttemptEnd(
5029                            WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED,
5030                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5031                    mWifiInjector.getWifiLastResortWatchdog()
5032                            .noteConnectionFailureAndTriggerIfNeeded(
5033                                    getTargetSsid(), mTargetRoamBSSID,
5034                                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
5035                    break;
5036                case WifiMonitor.SSID_REENABLED:
5037                    Log.d(TAG, "Supplicant SSID reenable:"
5038                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
5039                    // Do not re-enable it in Quality Network Selection since framework has its own
5040                    // Algorithm of disable/enable
5041                    break;
5042                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5043                    SupplicantState state = handleSupplicantStateChange(message);
5044                    // A driver/firmware hang can now put the interface in a down state.
5045                    // We detect the interface going down and recover from it
5046                    if (!SupplicantState.isDriverActive(state)) {
5047                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5048                            handleNetworkDisconnect();
5049                        }
5050                        log("Detected an interface down, restart driver");
5051                        // Rely on the fact that this will force us into killing supplicant and then
5052                        // restart supplicant from a clean state.
5053                        transitionTo(mSupplicantStoppingState);
5054                        sendMessage(CMD_START_SUPPLICANT);
5055                        break;
5056                    }
5057
5058                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
5059                    // when authentication times out after a successful connection,
5060                    // we can figure this from the supplicant state. If supplicant
5061                    // state is DISCONNECTED, but the mNetworkInfo says we are not
5062                    // disconnected, we need to handle a disconnection
5063                    if (!isLinkDebouncing() && state == SupplicantState.DISCONNECTED &&
5064                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
5065                        if (mVerboseLoggingEnabled) {
5066                            log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
5067                        }
5068                        handleNetworkDisconnect();
5069                        transitionTo(mDisconnectedState);
5070                    }
5071
5072                    // If we have COMPLETED a connection to a BSSID, start doing
5073                    // DNAv4/DNAv6 -style probing for on-link neighbors of
5074                    // interest (e.g. routers); harmless if none are configured.
5075                    if (state == SupplicantState.COMPLETED) {
5076                        mIpManager.confirmConfiguration();
5077                    }
5078                    break;
5079                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5080                    if (message.arg1 == 1) {
5081                        mWifiNative.disconnect();
5082                        mTemporarilyDisconnectWifi = true;
5083                    } else {
5084                        mWifiNative.reconnect();
5085                        mTemporarilyDisconnectWifi = false;
5086                    }
5087                    break;
5088                case CMD_ADD_OR_UPDATE_NETWORK:
5089                    // Only the current foreground user can modify networks.
5090                    if (!mWifiConfigManager.isCurrentUserProfile(
5091                            UserHandle.getUserId(message.sendingUid))) {
5092                        loge("Only the current foreground user can modify networks "
5093                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5094                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5095                        replyToMessage(message, message.what, FAILURE);
5096                        break;
5097                    }
5098
5099                    config = (WifiConfiguration) message.obj;
5100
5101                    if (!recordUidIfAuthorized(config, message.sendingUid,
5102                            /* onlyAnnotate */ false)) {
5103                        logw("Not authorized to update network "
5104                             + " config=" + config.SSID
5105                             + " cnid=" + config.networkId
5106                             + " uid=" + message.sendingUid);
5107                        replyToMessage(message, message.what, FAILURE);
5108                        break;
5109                    }
5110
5111                    int res = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5112                    if (res < 0) {
5113                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5114                    } else {
5115                        WifiConfiguration curConfig = getCurrentWifiConfiguration();
5116                        if (curConfig != null && config != null) {
5117                            WifiConfiguration.NetworkSelectionStatus networkStatus =
5118                                    config.getNetworkSelectionStatus();
5119                            if (curConfig.priority < config.priority && networkStatus != null
5120                                    && !networkStatus.isNetworkPermanentlyDisabled()) {
5121                                // Interpret this as a connect attempt
5122                                // Set the last selected configuration so as to allow the system to
5123                                // stick the last user choice without persisting the choice
5124                                mWifiConfigManager.setAndEnableLastSelectedConfiguration(res);
5125                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
5126                                boolean persist = mWifiConfigManager
5127                                        .checkConfigOverridePermission(message.sendingUid);
5128                                if (mWifiConnectivityManager != null) {
5129                                    mWifiConnectivityManager.connectToUserSelectNetwork(res,
5130                                            persist);
5131                                }
5132
5133                                // Remember time of last connection attempt
5134                                lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5135                                mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5136
5137                                // As a courtesy to the caller, trigger a scan now
5138                                startScan(ADD_OR_UPDATE_SOURCE, 0, null, WIFI_WORK_SOURCE);
5139                            }
5140                        }
5141                    }
5142                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
5143                    break;
5144                case CMD_REMOVE_NETWORK:
5145                    // Only the current foreground user can modify networks.
5146                    if (!mWifiConfigManager.isCurrentUserProfile(
5147                            UserHandle.getUserId(message.sendingUid))) {
5148                        loge("Only the current foreground user can modify networks "
5149                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5150                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5151                        replyToMessage(message, message.what, FAILURE);
5152                        break;
5153                    }
5154                    netId = message.arg1;
5155
5156                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
5157                            /* onlyAnnotate */ false)) {
5158                        logw("Not authorized to remove network "
5159                             + " cnid=" + netId
5160                             + " uid=" + message.sendingUid);
5161                        replyToMessage(message, message.what, FAILURE);
5162                        break;
5163                    }
5164
5165                    ok = mWifiConfigManager.removeNetwork(message.arg1);
5166                    if (!ok) {
5167                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5168                    }
5169                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5170                    break;
5171                case CMD_ENABLE_NETWORK:
5172                    // Only the current foreground user can modify networks.
5173                    if (!mWifiConfigManager.isCurrentUserProfile(
5174                            UserHandle.getUserId(message.sendingUid))) {
5175                        loge("Only the current foreground user can modify networks "
5176                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5177                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5178                        replyToMessage(message, message.what, FAILURE);
5179                        break;
5180                    }
5181
5182                    boolean disableOthers = message.arg2 == 1;
5183                    netId = message.arg1;
5184                    config = mWifiConfigManager.getWifiConfiguration(netId);
5185                    if (config == null) {
5186                        loge("No network with id = " + netId);
5187                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5188                        replyToMessage(message, message.what, FAILURE);
5189                        break;
5190                    }
5191                    // disable other only means select this network, does not mean all other
5192                    // networks need to be disabled
5193                    if (disableOthers) {
5194                        // Remember time of last connection attempt
5195                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5196                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5197                    }
5198                    // Cancel auto roam requests
5199                    autoRoamSetBSSID(netId, "any");
5200
5201                    ok = mWifiConfigManager.enableNetwork(
5202                            config, disableOthers, message.sendingUid);
5203                    if (!ok) {
5204                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5205                    } else if (disableOthers) {
5206                        mTargetNetworkId = netId;
5207                    }
5208
5209                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5210                    break;
5211                case CMD_ENABLE_ALL_NETWORKS:
5212                    long time = android.os.SystemClock.elapsedRealtime();
5213                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
5214                        mWifiConfigManager.enableAllNetworks();
5215                        mLastEnableAllNetworksTime = time;
5216                    }
5217                    break;
5218                case WifiManager.DISABLE_NETWORK:
5219                    if (mWifiConfigManager.updateNetworkSelectionStatus(message.arg1,
5220                            WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) {
5221                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
5222                    } else {
5223                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5224                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5225                                WifiManager.ERROR);
5226                    }
5227                    break;
5228                case CMD_DISABLE_EPHEMERAL_NETWORK:
5229                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
5230                    if (config != null) {
5231                        if (config.networkId == mLastNetworkId) {
5232                            // Disconnect and let autojoin reselect a new network
5233                            sendMessage(CMD_DISCONNECT);
5234                        }
5235                    }
5236                    break;
5237                case CMD_BLACKLIST_NETWORK:
5238                    mWifiConfigManager.blackListBssid((String) message.obj);
5239                    break;
5240                case CMD_CLEAR_BLACKLIST:
5241                    mWifiConfigManager.clearBssidBlacklist();
5242                    break;
5243                case CMD_SAVE_CONFIG:
5244                    ok = mWifiConfigManager.saveConfig();
5245
5246                    if (mVerboseLoggingEnabled) logd("did save config " + ok);
5247                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
5248
5249                    // Inform the backup manager about a data change
5250                    mBackupManagerProxy.notifyDataChanged();
5251                    break;
5252                case CMD_GET_CONFIGURED_NETWORKS:
5253                    replyToMessage(message, message.what,
5254                            mWifiConfigManager.getSavedNetworks());
5255                    break;
5256                case WifiMonitor.SUP_REQUEST_IDENTITY:
5257                    int networkId = message.arg2;
5258                    boolean identitySent = false;
5259                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
5260
5261                    if (targetWificonfiguration != null
5262                            && targetWificonfiguration.enterpriseConfig != null) {
5263                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
5264                    }
5265
5266                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
5267                    if (targetWificonfiguration != null
5268                            && targetWificonfiguration.networkId == networkId
5269                            && (targetWificonfiguration.allowedKeyManagement
5270                                    .get(WifiConfiguration.KeyMgmt.WPA_EAP)
5271                            || targetWificonfiguration.allowedKeyManagement
5272                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X))
5273                            && TelephonyUtil.isSimEapMethod(eapMethod)) {
5274                        String identity =
5275                                TelephonyUtil.getSimIdentity(getTelephonyManager(), eapMethod);
5276                        if (identity != null) {
5277                            mWifiNative.simIdentityResponse(networkId, identity);
5278                            identitySent = true;
5279                        }
5280                    }
5281                    if (!identitySent) {
5282                        // Supplicant lacks credentials to connect to that network, hence black list
5283                        ssid = (String) message.obj;
5284                        if (targetWificonfiguration != null && ssid != null
5285                                && targetWificonfiguration.SSID != null
5286                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
5287                            mWifiConfigManager.updateNetworkSelectionStatus(targetWificonfiguration,
5288                                    WifiConfiguration.NetworkSelectionStatus
5289                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
5290                        }
5291                        // Disconnect now, as we don't have any way to fullfill
5292                        // the  supplicant request.
5293                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
5294                                WifiConfiguration.INVALID_NETWORK_ID);
5295                        mWifiNative.disconnect();
5296                    }
5297                    break;
5298                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5299                    logd("Received SUP_REQUEST_SIM_AUTH");
5300                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5301                    if (requestData != null) {
5302                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5303                            handleGsmAuthRequest(requestData);
5304                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5305                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5306                            handle3GAuthRequest(requestData);
5307                        }
5308                    } else {
5309                        loge("Invalid sim auth request");
5310                    }
5311                    break;
5312                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5313                    replyToMessage(message, message.what,
5314                            mWifiConfigManager.getPrivilegedSavedNetworks());
5315                    break;
5316                case CMD_GET_MATCHING_CONFIG:
5317                    replyToMessage(message, message.what,
5318                            mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
5319                    break;
5320                case CMD_RECONNECT:
5321                    if (mWifiConnectivityManager != null) {
5322                        mWifiConnectivityManager.forceConnectivityScan();
5323                    }
5324                    break;
5325                case CMD_REASSOCIATE:
5326                    lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5327                    mWifiNative.reassociate();
5328                    break;
5329                case CMD_RELOAD_TLS_AND_RECONNECT:
5330                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
5331                        logd("Reconnecting to give a chance to un-connected TLS networks");
5332                        mWifiNative.disconnect();
5333                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5334                        mWifiNative.reconnect();
5335                    }
5336                    break;
5337                case CMD_AUTO_ROAM:
5338                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5339                    return HANDLED;
5340                case CMD_AUTO_CONNECT:
5341                    /* Work Around: wpa_supplicant can get in a bad state where it returns a non
5342                     * associated status to the STATUS command but somehow-someplace still thinks
5343                     * it is associated and thus will ignore select/reconnect command with
5344                     * following message:
5345                     * "Already associated with the selected network - do nothing"
5346                     *
5347                     * Hence, sends a disconnect to supplicant first.
5348                     */
5349                    didDisconnect = false;
5350                    if (getCurrentState() != mDisconnectedState) {
5351                        /** Supplicant will ignore the reconnect if we are currently associated,
5352                         * hence trigger a disconnect
5353                         */
5354                        didDisconnect = true;
5355                        mWifiNative.disconnect();
5356                    }
5357
5358                    /* connect command coming from auto-join */
5359                    netId = message.arg1;
5360                    mTargetNetworkId = netId;
5361                    mTargetRoamBSSID = (String) message.obj;
5362                    config = mWifiConfigManager.getWifiConfiguration(netId);
5363                    logd("CMD_AUTO_CONNECT sup state "
5364                            + mSupplicantStateTracker.getSupplicantStateName()
5365                            + " my state " + getCurrentState().getName()
5366                            + " nid=" + Integer.toString(netId)
5367                            + " roam=" + Boolean.toString(mAutoRoaming));
5368                    if (config == null) {
5369                        loge("AUTO_CONNECT and no config, bail out...");
5370                        break;
5371                    }
5372
5373                    /* Make sure we cancel any previous roam request */
5374                    setTargetBssid(config, mTargetRoamBSSID);
5375
5376                    /* Save the network config */
5377                    logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
5378                            + " nid=" + Integer.toString(netId));
5379                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
5380                    netId = result.getNetworkId();
5381                    logd("CMD_AUTO_CONNECT did save config -> "
5382                            + " nid=" + Integer.toString(netId));
5383
5384                    // Since we updated the config,read it back from config store:
5385                    config = mWifiConfigManager.getWifiConfiguration(netId);
5386                    if (config == null) {
5387                        loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
5388                        break;
5389                    }
5390                    if (netId != config.networkId) {
5391                        loge("CMD_AUTO_CONNECT couldn't update the config, want"
5392                                + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
5393                        break;
5394                    }
5395
5396                    if (deferForUserInput(message, netId, false)) {
5397                        break;
5398                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5399                                                                   WifiConfiguration.USER_BANNED) {
5400                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5401                                WifiManager.NOT_AUTHORIZED);
5402                        break;
5403                    }
5404
5405                    // If we're autojoining a network that the user or an app explicitly selected,
5406                    // keep track of the UID that selected it.
5407                    // TODO(b/26786318): Keep track of the lastSelectedConfiguration and the
5408                    // lastConnectUid on a per-user basis.
5409                    int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
5410
5411                    //Start a new ConnectionEvent due to auto_connect, assume we are connecting
5412                    //between different networks due to QNS, setting ROAM_UNRELATED
5413                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5414                            WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
5415                    if (!didDisconnect) {
5416                        //If we were originally disconnected, then this was not any kind of ROAM
5417                        mWifiMetrics.setConnectionEventRoamType(
5418                                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
5419                    }
5420                    //Determine if this CONNECTION is for a user selection
5421                    if (mWifiConfigManager.isLastSelectedConfiguration(config)
5422                            && mWifiConfigManager.isCurrentUserProfile(
5423                                    UserHandle.getUserId(config.lastConnectUid))) {
5424                        lastConnectUid = config.lastConnectUid;
5425                        mWifiMetrics.setConnectionEventRoamType(
5426                                WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
5427                    }
5428                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
5429                            lastConnectUid) && mWifiNative.reconnect()) {
5430                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5431                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
5432                        config = mWifiConfigManager.getWifiConfiguration(netId);
5433                        if (config != null
5434                                && !mWifiConfigManager.isLastSelectedConfiguration(config)) {
5435                            // If we autojoined a different config than the user selected one,
5436                            // it means we could not see the last user selection,
5437                            // or that the last user selection was faulty and ended up blacklisted
5438                            // for some reason (in which case the user is notified with an error
5439                            // message in the Wifi picker), and thus we managed to auto-join away
5440                            // from the selected  config. -> in that case we need to forget
5441                            // the selection because we don't want to abruptly switch back to it.
5442                            //
5443                            // Note that the user selection is also forgotten after a period of time
5444                            // during which the device has been disconnected.
5445                            // The default value is 30 minutes : see the code path at bottom of
5446                            // setScanResults() function.
5447                            mWifiConfigManager.
5448                                 setAndEnableLastSelectedConfiguration(
5449                                         WifiConfiguration.INVALID_NETWORK_ID);
5450                        }
5451                        mAutoRoaming = false;
5452                        if (isRoaming() || isLinkDebouncing()) {
5453                            transitionTo(mRoamingState);
5454                        } else if (didDisconnect) {
5455                            transitionTo(mDisconnectingState);
5456                        }
5457                    } else {
5458                        loge("Failed to connect config: " + config + " netId: " + netId);
5459                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5460                                WifiManager.ERROR);
5461                        reportConnectionAttemptEnd(
5462                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5463                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5464                        break;
5465                    }
5466                    break;
5467                case CMD_REMOVE_APP_CONFIGURATIONS:
5468                    mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
5469                    break;
5470                case CMD_REMOVE_USER_CONFIGURATIONS:
5471                    mWifiConfigManager.removeNetworksForUser(message.arg1);
5472                    break;
5473                case WifiManager.CONNECT_NETWORK:
5474                    // Only the current foreground user and System UI (which runs as user 0 but acts
5475                    // on behalf of the current foreground user) can modify networks.
5476                    if (!mWifiConfigManager.isCurrentUserProfile(
5477                            UserHandle.getUserId(message.sendingUid)) &&
5478                            message.sendingUid != mSystemUiUid) {
5479                        loge("Only the current foreground user can modify networks "
5480                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5481                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5482                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5483                                       WifiManager.NOT_AUTHORIZED);
5484                        break;
5485                    }
5486
5487                    /**
5488                     *  The connect message can contain a network id passed as arg1 on message or
5489                     * or a config passed as obj on message.
5490                     * For a new network, a config is passed to create and connect.
5491                     * For an existing network, a network id is passed
5492                     */
5493                    netId = message.arg1;
5494                    config = (WifiConfiguration) message.obj;
5495                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5496                    boolean updatedExisting = false;
5497
5498                    /* Save the network config */
5499                    if (config != null) {
5500                        // When connecting to an access point, WifiStateMachine wants to update the
5501                        // relevant config with administrative data. This update should not be
5502                        // considered a 'real' update, therefore lockdown by Device Owner must be
5503                        // disregarded.
5504                        if (!recordUidIfAuthorized(config, message.sendingUid,
5505                                /* onlyAnnotate */ true)) {
5506                            logw("Not authorized to update network "
5507                                 + " config=" + config.SSID
5508                                 + " cnid=" + config.networkId
5509                                 + " uid=" + message.sendingUid);
5510                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5511                                           WifiManager.NOT_AUTHORIZED);
5512                            break;
5513                        }
5514                        String configKey = config.configKey(true /* allowCached */);
5515                        WifiConfiguration savedConfig =
5516                                mWifiConfigManager.getWifiConfiguration(configKey);
5517                        if (savedConfig != null) {
5518                            // There is an existing config with this netId, but it wasn't exposed
5519                            // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigManager#
5520                            // getConfiguredNetworks). Remove those bits and update the config.
5521                            config = savedConfig;
5522                            logd("CONNECT_NETWORK updating existing config with id=" +
5523                                    config.networkId + " configKey=" + configKey);
5524                            config.ephemeral = false;
5525                            mWifiConfigManager.updateNetworkSelectionStatus(config,
5526                                    WifiConfiguration.NetworkSelectionStatus
5527                                    .NETWORK_SELECTION_ENABLE);
5528                            updatedExisting = true;
5529                        }
5530
5531                        result = mWifiConfigManager.saveNetwork(config, message.sendingUid);
5532                        netId = result.getNetworkId();
5533                    }
5534                    config = mWifiConfigManager.getWifiConfiguration(netId);
5535                    if (config == null) {
5536                        logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
5537                                + mSupplicantStateTracker.getSupplicantStateName() + " my state "
5538                                + getCurrentState().getName());
5539                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5540                                WifiManager.ERROR);
5541                        break;
5542                    }
5543                    mTargetNetworkId = netId;
5544                    autoRoamSetBSSID(netId, "any");
5545                    if (message.sendingUid == Process.WIFI_UID
5546                        || message.sendingUid == Process.SYSTEM_UID) {
5547                        // As a sanity measure, clear the BSSID in the supplicant network block.
5548                        // If system or Wifi Settings want to connect, they will not
5549                        // specify the BSSID.
5550                        // If an app however had added a BSSID to this configuration, and the BSSID
5551                        // was wrong, Then we would forever fail to connect until that BSSID
5552                        // is cleaned up.
5553                        clearConfigBSSID(config, "CONNECT_NETWORK");
5554                    }
5555
5556                    if (deferForUserInput(message, netId, true)) {
5557                        break;
5558                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
5559                                                                    WifiConfiguration.USER_BANNED) {
5560                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5561                                WifiManager.NOT_AUTHORIZED);
5562                        break;
5563                    }
5564
5565                    mAutoRoaming = false;
5566
5567                    /* Tell network selection the user did try to connect to that network if from
5568                    settings */
5569                    boolean persist =
5570                        mWifiConfigManager.checkConfigOverridePermission(message.sendingUid);
5571
5572
5573                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(netId);
5574                    if (mWifiConnectivityManager != null) {
5575                        mWifiConnectivityManager.connectToUserSelectNetwork(netId, persist);
5576                    }
5577                    didDisconnect = false;
5578                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
5579                            && mLastNetworkId != netId) {
5580                        /** Supplicant will ignore the reconnect if we are currently associated,
5581                         * hence trigger a disconnect
5582                         */
5583                        didDisconnect = true;
5584                        mWifiNative.disconnect();
5585                    }
5586
5587                    //Start a new ConnectionEvent due to connect_network, this is always user
5588                    //selected
5589                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5590                            WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
5591                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ true,
5592                            message.sendingUid) && mWifiNative.reconnect()) {
5593                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5594                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
5595
5596                        /* The state tracker handles enabling networks upon completion/failure */
5597                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
5598                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
5599                        if (didDisconnect) {
5600                            /* Expect a disconnection from the old connection */
5601                            transitionTo(mDisconnectingState);
5602                        } else if (updatedExisting && getCurrentState() == mConnectedState &&
5603                                getCurrentWifiConfiguration().networkId == netId) {
5604                            // Update the current set of network capabilities, but stay in the
5605                            // current state.
5606                            updateCapabilities(config);
5607                        } else {
5608                            /**
5609                             * Directly go to disconnected state where we
5610                             * process the connection events from supplicant
5611                             */
5612                            transitionTo(mDisconnectedState);
5613                        }
5614                    } else {
5615                        loge("Failed to connect config: " + config + " netId: " + netId);
5616                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5617                                WifiManager.ERROR);
5618                        reportConnectionAttemptEnd(
5619                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5620                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5621                        break;
5622                    }
5623                    break;
5624                case WifiManager.SAVE_NETWORK:
5625                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5626                    // Fall thru
5627                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
5628                    // Only the current foreground user can modify networks.
5629                    if (!mWifiConfigManager.isCurrentUserProfile(
5630                            UserHandle.getUserId(message.sendingUid))) {
5631                        loge("Only the current foreground user can modify networks "
5632                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5633                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5634                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5635                                WifiManager.NOT_AUTHORIZED);
5636                        break;
5637                    }
5638
5639                    lastSavedConfigurationAttempt = null; // Used for debug
5640                    config = (WifiConfiguration) message.obj;
5641                    if (config == null) {
5642                        loge("ERROR: SAVE_NETWORK with null configuration"
5643                                + mSupplicantStateTracker.getSupplicantStateName()
5644                                + " my state " + getCurrentState().getName());
5645                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5646                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5647                                WifiManager.ERROR);
5648                        break;
5649                    }
5650                    lastSavedConfigurationAttempt = new WifiConfiguration(config);
5651                    int nid = config.networkId;
5652                    logd("SAVE_NETWORK id=" + Integer.toString(nid)
5653                                + " config=" + config.SSID
5654                                + " nid=" + config.networkId
5655                                + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
5656                                + " my state " + getCurrentState().getName());
5657
5658                    // Only record the uid if this is user initiated
5659                    boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
5660                    if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
5661                            /* onlyAnnotate */ false)) {
5662                        logw("Not authorized to update network "
5663                             + " config=" + config.SSID
5664                             + " cnid=" + config.networkId
5665                             + " uid=" + message.sendingUid);
5666                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5667                                       WifiManager.NOT_AUTHORIZED);
5668                        break;
5669                    }
5670
5671                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
5672                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
5673                        if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
5674                            if (result.hasIpChanged()) {
5675                                // The currently connection configuration was changed
5676                                // We switched from DHCP to static or from static to DHCP, or the
5677                                // static IP address has changed.
5678                                log("Reconfiguring IP on connection");
5679                                // TODO: clear addresses and disable IPv6
5680                                // to simplify obtainingIpState.
5681                                transitionTo(mObtainingIpState);
5682                            }
5683                            if (result.hasProxyChanged()) {
5684                                log("Reconfiguring proxy on connection");
5685                                mIpManager.setHttpProxy(
5686                                        mWifiConfigManager.getProxyProperties(mLastNetworkId));
5687                            }
5688                        }
5689                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
5690                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
5691
5692                        if (mVerboseLoggingEnabled) {
5693                           logd("Success save network nid="
5694                                    + Integer.toString(result.getNetworkId()));
5695                        }
5696
5697                        /**
5698                         * If the command comes from WifiManager, then
5699                         * tell autojoin the user did try to modify and save that network,
5700                         * and interpret the SAVE_NETWORK as a request to connect
5701                         */
5702                        boolean user = message.what == WifiManager.SAVE_NETWORK;
5703
5704                        // Did this connect come from settings
5705                        boolean persistConnect =
5706                                mWifiConfigManager.checkConfigOverridePermission(
5707                                        message.sendingUid);
5708
5709                        if (user) {
5710                            mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
5711                            mWifiConfigManager.writeKnownNetworkHistory();
5712                        }
5713
5714                        if (mWifiConnectivityManager != null) {
5715                            mWifiConnectivityManager.connectToUserSelectNetwork(
5716                                    result.getNetworkId(), persistConnect);
5717                        }
5718                    } else {
5719                        loge("Failed to save network");
5720                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5721                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5722                                WifiManager.ERROR);
5723                    }
5724                    break;
5725                case WifiManager.FORGET_NETWORK:
5726                    // Only the current foreground user can modify networks.
5727                    if (!mWifiConfigManager.isCurrentUserProfile(
5728                            UserHandle.getUserId(message.sendingUid))) {
5729                        loge("Only the current foreground user can modify networks "
5730                                + " currentUserId=" + mWifiConfigManager.getCurrentUserId()
5731                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
5732                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5733                                WifiManager.NOT_AUTHORIZED);
5734                        break;
5735                    }
5736
5737                    // Debug only, remember last configuration that was forgotten
5738                    WifiConfiguration toRemove
5739                            = mWifiConfigManager.getWifiConfiguration(message.arg1);
5740                    if (toRemove == null) {
5741                        lastForgetConfigurationAttempt = null;
5742                    } else {
5743                        lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
5744                    }
5745                    // check that the caller owns this network
5746                    netId = message.arg1;
5747
5748                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
5749                            /* onlyAnnotate */ false)) {
5750                        logw("Not authorized to forget network "
5751                             + " cnid=" + netId
5752                             + " uid=" + message.sendingUid);
5753                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5754                                WifiManager.NOT_AUTHORIZED);
5755                        break;
5756                    }
5757
5758                    if (mWifiConfigManager.forgetNetwork(message.arg1)) {
5759                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
5760                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
5761                                (WifiConfiguration) message.obj);
5762                    } else {
5763                        loge("Failed to forget network");
5764                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5765                                WifiManager.ERROR);
5766                    }
5767                    break;
5768                case WifiManager.START_WPS:
5769                    WpsInfo wpsInfo = (WpsInfo) message.obj;
5770                    WpsResult wpsResult;
5771                    switch (wpsInfo.setup) {
5772                        case WpsInfo.PBC:
5773                            wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
5774                            break;
5775                        case WpsInfo.KEYPAD:
5776                            wpsResult = mWifiConfigManager.startWpsWithPinFromAccessPoint(wpsInfo);
5777                            break;
5778                        case WpsInfo.DISPLAY:
5779                            wpsResult = mWifiConfigManager.startWpsWithPinFromDevice(wpsInfo);
5780                            break;
5781                        default:
5782                            wpsResult = new WpsResult(Status.FAILURE);
5783                            loge("Invalid setup for WPS");
5784                            break;
5785                    }
5786                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
5787                            (WifiConfiguration.INVALID_NETWORK_ID);
5788                    if (wpsResult.status == Status.SUCCESS) {
5789                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
5790                        transitionTo(mWpsRunningState);
5791                    } else {
5792                        loge("Failed to start WPS with config " + wpsInfo.toString());
5793                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
5794                    }
5795                    break;
5796                case CMD_ASSOCIATED_BSSID:
5797                    // This is where we can confirm the connection BSSID. Use it to find the
5798                    // right ScanDetail to populate metrics.
5799                    String someBssid = (String) message.obj;
5800                    if (someBssid != null) {
5801                        //Get the config associated with this connection attempt
5802                        WifiConfiguration someConf =
5803                                mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
5804                        // Get the ScanDetail associated with this BSSID
5805                        ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCache(
5806                                someConf);
5807                        if (scanDetailCache != null) {
5808                            mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
5809                                    someBssid));
5810                        }
5811                    }
5812                    return NOT_HANDLED;
5813                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5814                    if (mVerboseLoggingEnabled) log("Network connection established");
5815                    mLastNetworkId = message.arg1;
5816                    mLastBssid = (String) message.obj;
5817
5818                    mWifiInfo.setBSSID(mLastBssid);
5819                    mWifiInfo.setNetworkId(mLastNetworkId);
5820                    if (mWifiConnectivityManager != null) {
5821                        mWifiConnectivityManager.trackBssid(mLastBssid, true);
5822                    }
5823                    sendNetworkStateChangeBroadcast(mLastBssid);
5824                    transitionTo(mObtainingIpState);
5825                    break;
5826                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5827                    // Calling handleNetworkDisconnect here is redundant because we might already
5828                    // have called it when leaving L2ConnectedState to go to disconnecting state
5829                    // or thru other path
5830                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
5831                    // if they are valid, and only in this case call handleNEtworkDisconnect,
5832                    // TODO: this should be fixed for a L MR release
5833                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
5834                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
5835                    // at the chip etc...
5836                    if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
5837                    handleNetworkDisconnect();
5838                    transitionTo(mDisconnectedState);
5839                    break;
5840                case CMD_ADD_PASSPOINT_MO:
5841                    res = mWifiConfigManager.addPasspointManagementObject((String) message.obj);
5842                    replyToMessage(message, message.what, res);
5843                    break;
5844                case CMD_MODIFY_PASSPOINT_MO:
5845                    if (message.obj != null) {
5846                        Bundle bundle = (Bundle) message.obj;
5847                        ArrayList<PasspointManagementObjectDefinition> mos =
5848                                bundle.getParcelableArrayList("MOS");
5849                        res = mWifiConfigManager.modifyPasspointMo(bundle.getString("FQDN"), mos);
5850                    } else {
5851                        res = 0;
5852                    }
5853                    replyToMessage(message, message.what, res);
5854
5855                    break;
5856                case CMD_QUERY_OSU_ICON:
5857                    if (mWifiConfigManager.queryPasspointIcon(
5858                            ((Bundle) message.obj).getLong("BSSID"),
5859                            ((Bundle) message.obj).getString("FILENAME"))) {
5860                        res = 1;
5861                    } else {
5862                        res = 0;
5863                    }
5864                    replyToMessage(message, message.what, res);
5865                    break;
5866                case CMD_MATCH_PROVIDER_NETWORK:
5867                    res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
5868                    replyToMessage(message, message.what, res);
5869                    break;
5870                default:
5871                    return NOT_HANDLED;
5872            }
5873            return HANDLED;
5874        }
5875    }
5876
5877    private void updateCapabilities(WifiConfiguration config) {
5878        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
5879        if (config != null) {
5880            if (config.ephemeral) {
5881                networkCapabilities.removeCapability(
5882                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5883            } else {
5884                networkCapabilities.addCapability(
5885                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5886            }
5887
5888            networkCapabilities.setSignalStrength(
5889                    (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI)
5890                    ? mWifiInfo.getRssi()
5891                    : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
5892        }
5893
5894        if (mWifiInfo.getMeteredHint()) {
5895            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5896        }
5897
5898        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
5899    }
5900
5901    private class WifiNetworkAgent extends NetworkAgent {
5902        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
5903                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
5904            super(l, c, TAG, ni, nc, lp, score, misc);
5905        }
5906
5907        @Override
5908        protected void unwanted() {
5909            // Ignore if we're not the current networkAgent.
5910            if (this != mNetworkAgent) return;
5911            if (mVerboseLoggingEnabled) {
5912                log("WifiNetworkAgent -> Wifi unwanted score " + Integer.toString(mWifiInfo.score));
5913            }
5914            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
5915        }
5916
5917        @Override
5918        protected void networkStatus(int status, String redirectUrl) {
5919            if (this != mNetworkAgent) return;
5920            if (status == NetworkAgent.INVALID_NETWORK) {
5921                if (mVerboseLoggingEnabled) {
5922                    log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
5923                            + Integer.toString(mWifiInfo.score));
5924                }
5925                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
5926            } else if (status == NetworkAgent.VALID_NETWORK) {
5927                if (mVerboseLoggingEnabled) {
5928                    log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
5929                            + Integer.toString(mWifiInfo.score));
5930                }
5931                doNetworkStatus(status);
5932            }
5933        }
5934
5935        @Override
5936        protected void saveAcceptUnvalidated(boolean accept) {
5937            if (this != mNetworkAgent) return;
5938            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
5939        }
5940
5941        @Override
5942        protected void startPacketKeepalive(Message msg) {
5943            WifiStateMachine.this.sendMessage(
5944                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5945        }
5946
5947        @Override
5948        protected void stopPacketKeepalive(Message msg) {
5949            WifiStateMachine.this.sendMessage(
5950                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5951        }
5952
5953        @Override
5954        protected void setSignalStrengthThresholds(int[] thresholds) {
5955            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
5956            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
5957            //    MAX_VALUE at the start/end of the thresholds array if necessary.
5958            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
5959            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
5960            //    re-arm the hardware event. This needs to be done on the state machine thread to
5961            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
5962            //    sent in the NetworkCapabilities) must be the one received from the hardware event
5963            //    received, or we might skip callbacks.
5964            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
5965            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
5966            if (thresholds.length == 0) {
5967                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5968                        mWifiInfo.getRssi());
5969                return;
5970            }
5971            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
5972            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
5973            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
5974            Arrays.sort(rssiVals);
5975            byte[] rssiRange = new byte[rssiVals.length];
5976            for (int i = 0; i < rssiVals.length; i++) {
5977                int val = rssiVals[i];
5978                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
5979                    rssiRange[i] = (byte) val;
5980                } else {
5981                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
5982                            + Arrays.toString(rssiVals));
5983                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5984                            mWifiInfo.getRssi());
5985                    return;
5986                }
5987            }
5988            // TODO: Do we quash rssi values in this sorted array which are very close?
5989            mRssiRanges = rssiRange;
5990            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
5991                    mWifiInfo.getRssi());
5992        }
5993
5994        @Override
5995        protected void preventAutomaticReconnect() {
5996            if (this != mNetworkAgent) return;
5997            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
5998        }
5999    }
6000
6001    void unwantedNetwork(int reason) {
6002        sendMessage(CMD_UNWANTED_NETWORK, reason);
6003    }
6004
6005    void doNetworkStatus(int status) {
6006        sendMessage(CMD_NETWORK_STATUS, status);
6007    }
6008
6009    // rfc4186 & rfc4187:
6010    // create Permanent Identity base on IMSI,
6011    // identity = usernam@realm
6012    // with username = prefix | IMSI
6013    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
6014    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
6015        String mcc;
6016        String mnc;
6017        String prefix;
6018
6019        if (imsi == null || imsi.isEmpty())
6020            return "";
6021
6022        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
6023            prefix = "1";
6024        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
6025            prefix = "0";
6026        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
6027            prefix = "6";
6028        else  // not a valide EapMethod
6029            return "";
6030
6031        /* extract mcc & mnc from mccMnc */
6032        if (mccMnc != null && !mccMnc.isEmpty()) {
6033            mcc = mccMnc.substring(0, 3);
6034            mnc = mccMnc.substring(3);
6035            if (mnc.length() == 2)
6036                mnc = "0" + mnc;
6037        } else {
6038            // extract mcc & mnc from IMSI, assume mnc size is 3
6039            mcc = imsi.substring(0, 3);
6040            mnc = imsi.substring(3, 6);
6041        }
6042
6043        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
6044    }
6045
6046    boolean startScanForConfiguration(WifiConfiguration config) {
6047        if (config == null)
6048            return false;
6049
6050        // We are still seeing a fairly high power consumption triggered by autojoin scans
6051        // Hence do partial scans only for PSK configuration that are roamable since the
6052        // primary purpose of the partial scans is roaming.
6053        // Full badn scans with exponential backoff for the purpose or extended roaming and
6054        // network switching are performed unconditionally.
6055        ScanDetailCache scanDetailCache =
6056                mWifiConfigManager.getScanDetailCache(config);
6057        if (scanDetailCache == null
6058                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
6059                || scanDetailCache.size() > 6) {
6060            //return true but to not trigger the scan
6061            return true;
6062        }
6063        HashSet<Integer> freqs = mWifiConfigManager.makeChannelList(config, ONE_HOUR_MILLI);
6064        if (freqs != null && freqs.size() != 0) {
6065            //if (mVerboseLoggingEnabled) {
6066            logd("starting scan for " + config.configKey() + " with " + freqs);
6067            //}
6068            Set<Integer> hiddenNetworkIds = new HashSet<>();
6069            if (config.hiddenSSID) {
6070                hiddenNetworkIds.add(config.networkId);
6071            }
6072            // Call wifi native to start the scan
6073            if (startScanNative(freqs, hiddenNetworkIds, WIFI_WORK_SOURCE)) {
6074                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
6075            } else {
6076                // used for debug only, mark scan as failed
6077                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
6078            }
6079            return true;
6080        } else {
6081            if (mVerboseLoggingEnabled) logd("no channels for " + config.configKey());
6082            return false;
6083        }
6084    }
6085
6086    void clearCurrentConfigBSSID(String dbg) {
6087        // Clear the bssid in the current config's network block
6088        WifiConfiguration config = getCurrentWifiConfiguration();
6089        if (config == null)
6090            return;
6091        clearConfigBSSID(config, dbg);
6092    }
6093    void clearConfigBSSID(WifiConfiguration config, String dbg) {
6094        if (config == null)
6095            return;
6096        if (mVerboseLoggingEnabled) {
6097            logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
6098                    + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
6099                    + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
6100        }
6101        if (mVerboseLoggingEnabled) {
6102           logd(dbg + " " + config.SSID
6103                    + " nid=" + Integer.toString(config.networkId));
6104        }
6105        mWifiConfigManager.saveWifiConfigBSSID(config, "any");
6106    }
6107
6108    class L2ConnectedState extends State {
6109        @Override
6110        public void enter() {
6111            mRssiPollToken++;
6112            if (mEnableRssiPolling) {
6113                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
6114            }
6115            if (mNetworkAgent != null) {
6116                loge("Have NetworkAgent when entering L2Connected");
6117                setNetworkDetailedState(DetailedState.DISCONNECTED);
6118            }
6119            setNetworkDetailedState(DetailedState.CONNECTING);
6120
6121            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
6122                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
6123                    mLinkProperties, 60, mNetworkMisc);
6124
6125            // We must clear the config BSSID, as the wifi chipset may decide to roam
6126            // from this point on and having the BSSID specified in the network block would
6127            // cause the roam to faile and the device to disconnect
6128            clearCurrentConfigBSSID("L2ConnectedState");
6129            mCountryCode.setReadyForChange(false);
6130            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
6131        }
6132
6133        @Override
6134        public void exit() {
6135            mIpManager.stop();
6136
6137            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
6138            // Bug: 15347363
6139            // For paranoia's sake, call handleNetworkDisconnect
6140            // only if BSSID is null or last networkId
6141            // is not invalid.
6142            if (mVerboseLoggingEnabled) {
6143                StringBuilder sb = new StringBuilder();
6144                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
6145                if (mLastBssid !=null) {
6146                    sb.append(" ").append(mLastBssid);
6147                }
6148            }
6149            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6150                handleNetworkDisconnect();
6151            }
6152            mCountryCode.setReadyForChange(true);
6153            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
6154        }
6155
6156        @Override
6157        public boolean processMessage(Message message) {
6158            logStateAndMessage(message, this);
6159
6160            switch (message.what) {
6161                case DhcpClient.CMD_PRE_DHCP_ACTION:
6162                    handlePreDhcpSetup();
6163                    break;
6164                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
6165                    mIpManager.completedPreDhcpAction();
6166                    break;
6167                case DhcpClient.CMD_POST_DHCP_ACTION:
6168                    handlePostDhcpSetup();
6169                    // We advance to mConnectedState because IpManager will also send a
6170                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
6171                    // which calls updateLinkProperties, which then sends
6172                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
6173                    //
6174                    // In the event of failure, we transition to mDisconnectingState
6175                    // similarly--via messages sent back from IpManager.
6176                    break;
6177                case CMD_IPV4_PROVISIONING_SUCCESS: {
6178                    handleIPv4Success((DhcpResults) message.obj);
6179                    sendNetworkStateChangeBroadcast(mLastBssid);
6180                    break;
6181                }
6182                case CMD_IPV4_PROVISIONING_FAILURE: {
6183                    handleIPv4Failure();
6184                    break;
6185                }
6186                case CMD_IP_CONFIGURATION_SUCCESSFUL:
6187                    handleSuccessfulIpConfiguration();
6188                    reportConnectionAttemptEnd(
6189                            WifiMetrics.ConnectionEvent.FAILURE_NONE,
6190                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6191                    sendConnectedState();
6192                    transitionTo(mConnectedState);
6193                    break;
6194                case CMD_IP_CONFIGURATION_LOST:
6195                    // Get Link layer stats so that we get fresh tx packet counters.
6196                    getWifiLinkLayerStats();
6197                    handleIpConfigurationLost();
6198                    reportConnectionAttemptEnd(
6199                            WifiMetrics.ConnectionEvent.FAILURE_DHCP,
6200                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6201                    transitionTo(mDisconnectingState);
6202                    break;
6203                case CMD_IP_REACHABILITY_LOST:
6204                    if (mVerboseLoggingEnabled && message.obj != null) log((String) message.obj);
6205                    handleIpReachabilityLost();
6206                    transitionTo(mDisconnectingState);
6207                    break;
6208                case CMD_DISCONNECT:
6209                    mWifiNative.disconnect();
6210                    transitionTo(mDisconnectingState);
6211                    break;
6212                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6213                    if (message.arg1 == 1) {
6214                        mWifiNative.disconnect();
6215                        mTemporarilyDisconnectWifi = true;
6216                        transitionTo(mDisconnectingState);
6217                    }
6218                    break;
6219                case CMD_SET_OPERATIONAL_MODE:
6220                    if (message.arg1 != CONNECT_MODE) {
6221                        sendMessage(CMD_DISCONNECT);
6222                        deferMessage(message);
6223                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE ||
6224                                message.arg1 == DISABLED_MODE) {
6225                            noteWifiDisabledWhileAssociated();
6226                        }
6227                    }
6228                    mWifiConfigManager.
6229                                setAndEnableLastSelectedConfiguration(
6230                                        WifiConfiguration.INVALID_NETWORK_ID);
6231                    break;
6232                    /* Ignore connection to same network */
6233                case WifiManager.CONNECT_NETWORK:
6234                    int netId = message.arg1;
6235                    if (mWifiInfo.getNetworkId() == netId) {
6236                        break;
6237                    }
6238                    return NOT_HANDLED;
6239                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6240                    mWifiInfo.setBSSID((String) message.obj);
6241                    mLastNetworkId = message.arg1;
6242                    mWifiInfo.setNetworkId(mLastNetworkId);
6243                    if(!mLastBssid.equals(message.obj)) {
6244                        mLastBssid = (String) message.obj;
6245                        sendNetworkStateChangeBroadcast(mLastBssid);
6246                    }
6247                    break;
6248                case CMD_RSSI_POLL:
6249                    if (message.arg1 == mRssiPollToken) {
6250                        if (mWifiConfigManager.mEnableChipWakeUpWhenAssociated.get()) {
6251                            if (mVerboseLoggingEnabled) {
6252                                log(" get link layer stats " + mWifiLinkLayerStatsSupported);
6253                            }
6254                            WifiLinkLayerStats stats = getWifiLinkLayerStats();
6255                            if (stats != null) {
6256                                // Sanity check the results provided by driver
6257                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
6258                                        && (stats.rssi_mgmt == 0
6259                                        || stats.beacon_rx == 0)) {
6260                                    stats = null;
6261                                }
6262                            }
6263                            // Get Info and continue polling
6264                            fetchRssiLinkSpeedAndFrequencyNative();
6265                            mWifiScoreReport =
6266                                    WifiScoreReport.calculateScore(mWifiInfo,
6267                                                                   getCurrentWifiConfiguration(),
6268                                                                   mWifiConfigManager,
6269                                                                   mNetworkAgent,
6270                                                                   mWifiScoreReport,
6271                                                                   mAggressiveHandover,
6272                                                                   mVerboseLoggingEnabled);
6273                        }
6274                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6275                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6276                        if (mVerboseLoggingEnabled) sendRssiChangeBroadcast(mWifiInfo.getRssi());
6277                    } else {
6278                        // Polling has completed
6279                    }
6280                    break;
6281                case CMD_ENABLE_RSSI_POLL:
6282                    cleanWifiScore();
6283                    if (mWifiConfigManager.mEnableRssiPollWhenAssociated.get()) {
6284                        mEnableRssiPolling = (message.arg1 == 1);
6285                    } else {
6286                        mEnableRssiPolling = false;
6287                    }
6288                    mRssiPollToken++;
6289                    if (mEnableRssiPolling) {
6290                        // First poll
6291                        fetchRssiLinkSpeedAndFrequencyNative();
6292                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
6293                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
6294                    }
6295                    break;
6296                case WifiManager.RSSI_PKTCNT_FETCH:
6297                    RssiPacketCountInfo info = new RssiPacketCountInfo();
6298                    fetchRssiLinkSpeedAndFrequencyNative();
6299                    info.rssi = mWifiInfo.getRssi();
6300                    fetchPktcntNative(info);
6301                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
6302                    break;
6303                case CMD_DELAYED_NETWORK_DISCONNECT:
6304                    if (!isLinkDebouncing()) {
6305
6306                        // Ignore if we are not debouncing
6307                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
6308                                + message.arg1);
6309                        return HANDLED;
6310                    } else {
6311                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
6312                                + message.arg1);
6313
6314                        mIsLinkDebouncing = false;
6315                        // If we are still debouncing while this message comes,
6316                        // it means we were not able to reconnect within the alloted time
6317                        // = LINK_FLAPPING_DEBOUNCE_MSEC
6318                        // and thus, trigger a real disconnect
6319                        handleNetworkDisconnect();
6320                        transitionTo(mDisconnectedState);
6321                    }
6322                    break;
6323                case CMD_ASSOCIATED_BSSID:
6324                    if ((String) message.obj == null) {
6325                        logw("Associated command w/o BSSID");
6326                        break;
6327                    }
6328                    mLastBssid = (String) message.obj;
6329                    if (mLastBssid != null && (mWifiInfo.getBSSID() == null
6330                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
6331                        mWifiInfo.setBSSID((String) message.obj);
6332                        sendNetworkStateChangeBroadcast(mLastBssid);
6333                    }
6334                    break;
6335                case CMD_START_RSSI_MONITORING_OFFLOAD:
6336                case CMD_RSSI_THRESHOLD_BREACH:
6337                    byte currRssi = (byte) message.arg1;
6338                    processRssiThreshold(currRssi, message.what);
6339                    break;
6340                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
6341                    stopRssiMonitoringOffload();
6342                    break;
6343                case CMD_RESET_SIM_NETWORKS:
6344                    if (message.arg1 == 0 // sim was removed
6345                            && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6346                        WifiConfiguration config =
6347                                mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6348                        if (TelephonyUtil.isSimConfig(config)) {
6349                            mWifiNative.disconnect();
6350                            transitionTo(mDisconnectingState);
6351                        }
6352                    }
6353                    /* allow parent state to reset data for other networks */
6354                    return NOT_HANDLED;
6355                default:
6356                    return NOT_HANDLED;
6357            }
6358
6359            return HANDLED;
6360        }
6361    }
6362
6363    class ObtainingIpState extends State {
6364        @Override
6365        public void enter() {
6366            if (mVerboseLoggingEnabled) {
6367                String key = "";
6368                if (getCurrentWifiConfiguration() != null) {
6369                    key = getCurrentWifiConfiguration().configKey();
6370                }
6371                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
6372                        + " " + key + " "
6373                        + " roam=" + mAutoRoaming
6374                        + " static=" + mWifiConfigManager.isUsingStaticIp(mLastNetworkId));
6375            }
6376
6377            // Reset link Debouncing, indicating we have successfully re-connected to the AP
6378            // We might still be roaming
6379            mIsLinkDebouncing = false;
6380
6381            // Send event to CM & network change broadcast
6382            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
6383
6384            // We must clear the config BSSID, as the wifi chipset may decide to roam
6385            // from this point on and having the BSSID specified in the network block would
6386            // cause the roam to fail and the device to disconnect.
6387            clearCurrentConfigBSSID("ObtainingIpAddress");
6388
6389            // Stop IpManager in case we're switching from DHCP to static
6390            // configuration or vice versa.
6391            //
6392            // TODO: Only ever enter this state the first time we connect to a
6393            // network, never on switching between static configuration and
6394            // DHCP. When we transition from static configuration to DHCP in
6395            // particular, we must tell ConnectivityService that we're
6396            // disconnected, because DHCP might take a long time during which
6397            // connectivity APIs such as getActiveNetworkInfo should not return
6398            // CONNECTED.
6399            stopIpManager();
6400
6401            mIpManager.setHttpProxy(mWifiConfigManager.getProxyProperties(mLastNetworkId));
6402            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
6403                mIpManager.setTcpBufferSizes(mTcpBufferSizes);
6404            }
6405
6406            if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
6407                final IpManager.ProvisioningConfiguration prov =
6408                        IpManager.buildProvisioningConfiguration()
6409                            .withPreDhcpAction()
6410                            .withApfCapabilities(mWifiNative.getApfCapabilities())
6411                            .build();
6412                mIpManager.startProvisioning(prov);
6413                // Get Link layer stats so as we get fresh tx packet counters
6414                getWifiLinkLayerStats();
6415            } else {
6416                StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(
6417                        mLastNetworkId);
6418                if (config.ipAddress == null) {
6419                    logd("Static IP lacks address");
6420                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
6421                } else {
6422                    final IpManager.ProvisioningConfiguration prov =
6423                            IpManager.buildProvisioningConfiguration()
6424                                .withStaticConfiguration(config)
6425                                .withApfCapabilities(mWifiNative.getApfCapabilities())
6426                                .build();
6427                    mIpManager.startProvisioning(prov);
6428                }
6429            }
6430        }
6431
6432        @Override
6433        public boolean processMessage(Message message) {
6434            logStateAndMessage(message, this);
6435
6436            switch(message.what) {
6437                case CMD_AUTO_CONNECT:
6438                case CMD_AUTO_ROAM:
6439                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6440                    break;
6441                case WifiManager.SAVE_NETWORK:
6442                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
6443                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6444                    deferMessage(message);
6445                    break;
6446                    /* Defer any power mode changes since we must keep active power mode at DHCP */
6447
6448                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6449                    reportConnectionAttemptEnd(
6450                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6451                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6452                    return NOT_HANDLED;
6453                case CMD_SET_HIGH_PERF_MODE:
6454                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6455                    deferMessage(message);
6456                    break;
6457                    /* Defer scan request since we should not switch to other channels at DHCP */
6458                case CMD_START_SCAN:
6459                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6460                    deferMessage(message);
6461                    break;
6462                default:
6463                    return NOT_HANDLED;
6464            }
6465            return HANDLED;
6466        }
6467    }
6468
6469    private void sendConnectedState() {
6470        // If this network was explicitly selected by the user, evaluate whether to call
6471        // explicitlySelected() so the system can treat it appropriately.
6472        WifiConfiguration config = getCurrentWifiConfiguration();
6473        if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
6474            boolean prompt =
6475                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
6476            if (mVerboseLoggingEnabled) {
6477                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
6478            }
6479            if (prompt) {
6480                // Selected by the user via Settings or QuickSettings. If this network has Internet
6481                // access, switch to it. Otherwise, switch to it only if the user confirms that they
6482                // really want to switch, or has already confirmed and selected "Don't ask again".
6483                if (mVerboseLoggingEnabled) {
6484                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
6485                }
6486                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
6487            }
6488        }
6489
6490        setNetworkDetailedState(DetailedState.CONNECTED);
6491        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
6492        sendNetworkStateChangeBroadcast(mLastBssid);
6493    }
6494
6495    class RoamingState extends State {
6496        boolean mAssociated;
6497        @Override
6498        public void enter() {
6499            if (mVerboseLoggingEnabled) {
6500                log("RoamingState Enter"
6501                        + " mScreenOn=" + mScreenOn );
6502            }
6503
6504            // Make sure we disconnect if roaming fails
6505            roamWatchdogCount++;
6506            logd("Start Roam Watchdog " + roamWatchdogCount);
6507            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
6508                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
6509            mAssociated = false;
6510        }
6511        @Override
6512        public boolean processMessage(Message message) {
6513            logStateAndMessage(message, this);
6514            WifiConfiguration config;
6515            switch (message.what) {
6516                case CMD_IP_CONFIGURATION_LOST:
6517                    config = getCurrentWifiConfiguration();
6518                    if (config != null) {
6519                        mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
6520                        mWifiConfigManager.noteRoamingFailure(config,
6521                                WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
6522                    }
6523                    return NOT_HANDLED;
6524                case CMD_UNWANTED_NETWORK:
6525                    if (mVerboseLoggingEnabled) {
6526                        log("Roaming and CS doesnt want the network -> ignore");
6527                    }
6528                    return HANDLED;
6529                case CMD_SET_OPERATIONAL_MODE:
6530                    if (message.arg1 != CONNECT_MODE) {
6531                        deferMessage(message);
6532                    }
6533                    break;
6534                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6535                    /**
6536                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
6537                     * before NETWORK_DISCONNECTION_EVENT
6538                     * And there is an associated BSSID corresponding to our target BSSID, then
6539                     * we have missed the network disconnection, transition to mDisconnectedState
6540                     * and handle the rest of the events there.
6541                     */
6542                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6543                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
6544                            || stateChangeResult.state == SupplicantState.INACTIVE
6545                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
6546                        if (mVerboseLoggingEnabled) {
6547                            log("STATE_CHANGE_EVENT in roaming state "
6548                                    + stateChangeResult.toString() );
6549                        }
6550                        if (stateChangeResult.BSSID != null
6551                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
6552                            handleNetworkDisconnect();
6553                            transitionTo(mDisconnectedState);
6554                        }
6555                    }
6556                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
6557                        // We completed the layer2 roaming part
6558                        mAssociated = true;
6559                        if (stateChangeResult.BSSID != null) {
6560                            mTargetRoamBSSID = stateChangeResult.BSSID;
6561                        }
6562                    }
6563                    break;
6564                case CMD_ROAM_WATCHDOG_TIMER:
6565                    if (roamWatchdogCount == message.arg1) {
6566                        if (mVerboseLoggingEnabled) log("roaming watchdog! -> disconnect");
6567                        mWifiMetrics.endConnectionEvent(
6568                                WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
6569                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6570                        mRoamFailCount++;
6571                        handleNetworkDisconnect();
6572                        mWifiNative.disconnect();
6573                        transitionTo(mDisconnectedState);
6574                    }
6575                    break;
6576                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6577                    if (mAssociated) {
6578                        if (mVerboseLoggingEnabled) {
6579                            log("roaming and Network connection established");
6580                        }
6581                        mLastNetworkId = message.arg1;
6582                        mLastBssid = (String) message.obj;
6583                        mWifiInfo.setBSSID(mLastBssid);
6584                        mWifiInfo.setNetworkId(mLastNetworkId);
6585                        if (mWifiConnectivityManager != null) {
6586                            mWifiConnectivityManager.trackBssid(mLastBssid, true);
6587                        }
6588                        sendNetworkStateChangeBroadcast(mLastBssid);
6589
6590                        // Successful framework roam! (probably)
6591                        reportConnectionAttemptEnd(
6592                                WifiMetrics.ConnectionEvent.FAILURE_NONE,
6593                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6594
6595                        // We must clear the config BSSID, as the wifi chipset may decide to roam
6596                        // from this point on and having the BSSID specified by QNS would cause
6597                        // the roam to fail and the device to disconnect.
6598                        // When transition from RoamingState to DisconnectingState or
6599                        // DisconnectedState, the config BSSID is cleared by
6600                        // handleNetworkDisconnect().
6601                        clearCurrentConfigBSSID("RoamingCompleted");
6602
6603                        // We used to transition to ObtainingIpState in an
6604                        // attempt to do DHCPv4 RENEWs on framework roams.
6605                        // DHCP can take too long to time out, and we now rely
6606                        // upon IpManager's use of IpReachabilityMonitor to
6607                        // confirm our current network configuration.
6608                        //
6609                        // mIpManager.confirmConfiguration() is called within
6610                        // the handling of SupplicantState.COMPLETED.
6611                        transitionTo(mConnectedState);
6612                    } else {
6613                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6614                    }
6615                    break;
6616                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6617                    // Throw away but only if it corresponds to the network we're roaming to
6618                    String bssid = (String) message.obj;
6619                    if (true) {
6620                        String target = "";
6621                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
6622                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
6623                                + " BSSID=" + bssid
6624                                + " target=" + target);
6625                    }
6626                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
6627                        handleNetworkDisconnect();
6628                        transitionTo(mDisconnectedState);
6629                    }
6630                    break;
6631                case WifiMonitor.SSID_TEMP_DISABLED:
6632                    // Auth error while roaming
6633                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
6634                            + " id=" + Integer.toString(message.arg1)
6635                            + " isRoaming=" + isRoaming()
6636                            + " roam=" + mAutoRoaming);
6637                    if (message.arg1 == mLastNetworkId) {
6638                        config = getCurrentWifiConfiguration();
6639                        if (config != null) {
6640                            mWifiDiagnostics.captureBugReportData(
6641                                    WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
6642                            mWifiConfigManager.noteRoamingFailure(config,
6643                                    WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
6644                        }
6645                        handleNetworkDisconnect();
6646                        transitionTo(mDisconnectingState);
6647                    }
6648                    return NOT_HANDLED;
6649                case CMD_START_SCAN:
6650                    deferMessage(message);
6651                    break;
6652                default:
6653                    return NOT_HANDLED;
6654            }
6655            return HANDLED;
6656        }
6657
6658        @Override
6659        public void exit() {
6660            logd("WifiStateMachine: Leaving Roaming state");
6661        }
6662    }
6663
6664    class ConnectedState extends State {
6665        @Override
6666        public void enter() {
6667            updateDefaultRouteMacAddress(1000);
6668            if (mVerboseLoggingEnabled) {
6669                log("Enter ConnectedState "
6670                       + " mScreenOn=" + mScreenOn);
6671            }
6672
6673            if (mWifiConnectivityManager != null) {
6674                mWifiConnectivityManager.handleConnectionStateChanged(
6675                        WifiConnectivityManager.WIFI_STATE_CONNECTED);
6676            }
6677            registerConnected();
6678            lastConnectAttemptTimestamp = 0;
6679            targetWificonfiguration = null;
6680            // Paranoia
6681            mIsLinkDebouncing = false;
6682
6683            // Not roaming anymore
6684            mAutoRoaming = false;
6685
6686            if (testNetworkDisconnect) {
6687                testNetworkDisconnectCounter++;
6688                logd("ConnectedState Enter start disconnect test " +
6689                        testNetworkDisconnectCounter);
6690                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
6691                        testNetworkDisconnectCounter, 0), 15000);
6692            }
6693
6694            // Reenable all networks, allow for hidden networks to be scanned
6695            mWifiConfigManager.enableAllNetworks();
6696
6697            mLastDriverRoamAttempt = 0;
6698            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
6699            mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
6700        }
6701        @Override
6702        public boolean processMessage(Message message) {
6703            WifiConfiguration config = null;
6704            logStateAndMessage(message, this);
6705
6706            switch (message.what) {
6707                case CMD_UNWANTED_NETWORK:
6708                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
6709                        mWifiConfigManager.handleBadNetworkDisconnectReport(
6710                                mLastNetworkId, mWifiInfo);
6711                        mWifiNative.disconnect();
6712                        transitionTo(mDisconnectingState);
6713                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
6714                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
6715                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
6716                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
6717                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
6718                        config = getCurrentWifiConfiguration();
6719                        if (config != null) {
6720                            // Disable autojoin
6721                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
6722                                config.validatedInternetAccess = false;
6723                                // Clear last-selected status, as being last-selected also avoids
6724                                // disabling auto-join.
6725                                if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
6726                                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(
6727                                        WifiConfiguration.INVALID_NETWORK_ID);
6728                                }
6729                                mWifiConfigManager.updateNetworkSelectionStatus(config,
6730                                        WifiConfiguration.NetworkSelectionStatus
6731                                        .DISABLED_NO_INTERNET);
6732                            }
6733                            config.numNoInternetAccessReports += 1;
6734                            mWifiConfigManager.writeKnownNetworkHistory();
6735                        }
6736                    }
6737                    return HANDLED;
6738                case CMD_NETWORK_STATUS:
6739                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
6740                        config = getCurrentWifiConfiguration();
6741                        if (config != null) {
6742                            // re-enable autojoin
6743                            config.numNoInternetAccessReports = 0;
6744                            config.validatedInternetAccess = true;
6745                            mWifiConfigManager.writeKnownNetworkHistory();
6746                        }
6747                    }
6748                    return HANDLED;
6749                case CMD_ACCEPT_UNVALIDATED:
6750                    boolean accept = (message.arg1 != 0);
6751                    config = getCurrentWifiConfiguration();
6752                    if (config != null) {
6753                        config.noInternetAccessExpected = accept;
6754                        mWifiConfigManager.writeKnownNetworkHistory();
6755                    }
6756                    return HANDLED;
6757                case CMD_TEST_NETWORK_DISCONNECT:
6758                    // Force a disconnect
6759                    if (message.arg1 == testNetworkDisconnectCounter) {
6760                        mWifiNative.disconnect();
6761                    }
6762                    break;
6763                case CMD_ASSOCIATED_BSSID:
6764                    // ASSOCIATING to a new BSSID while already connected, indicates
6765                    // that driver is roaming
6766                    mLastDriverRoamAttempt = mClock.getWallClockMillis();
6767                    return NOT_HANDLED;
6768                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6769                    long lastRoam = 0;
6770                    reportConnectionAttemptEnd(
6771                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6772                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6773                    if (mLastDriverRoamAttempt != 0) {
6774                        // Calculate time since last driver roam attempt
6775                        lastRoam = mClock.getWallClockMillis() - mLastDriverRoamAttempt;
6776                        mLastDriverRoamAttempt = 0;
6777                    }
6778                    if (unexpectedDisconnectedReason(message.arg2)) {
6779                        mWifiDiagnostics.captureBugReportData(
6780                                WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
6781                    }
6782                    config = getCurrentWifiConfiguration();
6783                    if (mWifiConfigManager.mEnableLinkDebouncing
6784                            && mScreenOn
6785                            && !isLinkDebouncing()
6786                            && config != null
6787                            && config.getNetworkSelectionStatus().isNetworkEnabled()
6788                            && !mWifiConfigManager.isLastSelectedConfiguration(config)
6789                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
6790                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
6791                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
6792                                    && mWifiInfo.getRssi() >
6793                                    WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
6794                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
6795                                    && mWifiInfo.getRssi() >
6796                                    mWifiConfigManager.mThresholdQualifiedRssi5.get()))) {
6797                        // Start de-bouncing the L2 disconnection:
6798                        // this L2 disconnection might be spurious.
6799                        // Hence we allow 4 seconds for the state machine to try
6800                        // to reconnect, go thru the
6801                        // roaming cycle and enter Obtaining IP address
6802                        // before signalling the disconnect to ConnectivityService and L3
6803                        startScanForConfiguration(getCurrentWifiConfiguration());
6804                        mIsLinkDebouncing = true;
6805
6806                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
6807                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
6808                        if (mVerboseLoggingEnabled) {
6809                            log("NETWORK_DISCONNECTION_EVENT in connected state"
6810                                    + " BSSID=" + mWifiInfo.getBSSID()
6811                                    + " RSSI=" + mWifiInfo.getRssi()
6812                                    + " freq=" + mWifiInfo.getFrequency()
6813                                    + " reason=" + message.arg2
6814                                    + " -> debounce");
6815                        }
6816                        return HANDLED;
6817                    } else {
6818                        if (mVerboseLoggingEnabled) {
6819                            log("NETWORK_DISCONNECTION_EVENT in connected state"
6820                                    + " BSSID=" + mWifiInfo.getBSSID()
6821                                    + " RSSI=" + mWifiInfo.getRssi()
6822                                    + " freq=" + mWifiInfo.getFrequency()
6823                                    + " was debouncing=" + isLinkDebouncing()
6824                                    + " reason=" + message.arg2
6825                                    + " Network Selection Status=" + (config == null ? "Unavailable"
6826                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
6827                        }
6828                    }
6829                    break;
6830                case CMD_AUTO_ROAM:
6831                    // Clear the driver roam indication since we are attempting a framework roam
6832                    mLastDriverRoamAttempt = 0;
6833
6834                    /*<TODO> 2016-02-24
6835                        Fix CMD_AUTO_ROAM to use the candidate (message.arg1) networkID, rather than
6836                        the old networkID.
6837                        The current code only handles roaming between BSSIDs on the same networkID,
6838                        and will break for roams between different (but linked) networkIDs. This
6839                        case occurs for DBDC roaming, and the CMD_AUTO_ROAM sent due to it will
6840                        fail.
6841                    */
6842                    /* Connect command coming from auto-join */
6843                    ScanResult candidate = (ScanResult)message.obj;
6844                    String bssid = "any";
6845                    if (candidate != null) {
6846                        bssid = candidate.BSSID;
6847                    }
6848                    int netId = message.arg1;
6849                    if (netId == WifiConfiguration.INVALID_NETWORK_ID) {
6850                        loge("AUTO_ROAM and no config, bail out...");
6851                        break;
6852                    } else {
6853                        config = mWifiConfigManager.getWifiConfiguration(netId);
6854                    }
6855
6856                    logd("CMD_AUTO_ROAM sup state "
6857                            + mSupplicantStateTracker.getSupplicantStateName()
6858                            + " my state " + getCurrentState().getName()
6859                            + " nid=" + Integer.toString(netId)
6860                            + " config " + config.configKey()
6861                            + " roam=" + Integer.toString(message.arg2)
6862                            + " to " + bssid
6863                            + " targetRoamBSSID " + mTargetRoamBSSID);
6864
6865                    setTargetBssid(config, bssid);
6866                    mTargetNetworkId = netId;
6867
6868                    /* Determine if this is a regular roam (between BSSIDs sharing the same SSID),
6869                       or a DBDC roam (between 2.4 & 5GHz networks on different SSID's, but with
6870                       matching 16 byte BSSID prefixes):
6871                     */
6872                    WifiConfiguration currentConfig = getCurrentWifiConfiguration();
6873                    if (currentConfig != null && currentConfig.isLinked(config)) {
6874                        // This is dual band roaming
6875                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
6876                                WifiMetricsProto.ConnectionEvent.ROAM_DBDC);
6877                    } else {
6878                        // This is regular roaming
6879                        mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
6880                                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
6881                    }
6882
6883                    if (deferForUserInput(message, netId, false)) {
6884                        reportConnectionAttemptEnd(
6885                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6886                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6887                        break;
6888                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
6889                            WifiConfiguration.USER_BANNED) {
6890                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6891                                WifiManager.NOT_AUTHORIZED);
6892                        reportConnectionAttemptEnd(
6893                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6894                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6895                        break;
6896                    }
6897
6898                    boolean ret = false;
6899                    if (mLastNetworkId != netId) {
6900                        if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
6901                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
6902                            ret = true;
6903                        }
6904                    } else {
6905                        ret = mWifiNative.reassociate();
6906                    }
6907                    if (ret) {
6908                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
6909                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
6910
6911                        // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
6912                        mAutoRoaming = true;
6913                        transitionTo(mRoamingState);
6914
6915                    } else {
6916                        loge("Failed to connect config: " + config + " netId: " + netId);
6917                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6918                                WifiManager.ERROR);
6919                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6920                        reportConnectionAttemptEnd(
6921                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6922                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6923                        break;
6924                    }
6925                    break;
6926                case CMD_START_IP_PACKET_OFFLOAD: {
6927                        int slot = message.arg1;
6928                        int intervalSeconds = message.arg2;
6929                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
6930                        byte[] dstMac;
6931                        try {
6932                            InetAddress gateway = RouteInfo.selectBestRoute(
6933                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
6934                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
6935                            dstMac = macAddressFromString(dstMacStr);
6936                        } catch (NullPointerException|IllegalArgumentException e) {
6937                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
6938                            mNetworkAgent.onPacketKeepaliveEvent(slot,
6939                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
6940                            break;
6941                        }
6942                        pkt.dstMac = dstMac;
6943                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
6944                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
6945                        break;
6946                    }
6947                default:
6948                    return NOT_HANDLED;
6949            }
6950            return HANDLED;
6951        }
6952
6953        @Override
6954        public void exit() {
6955            logd("WifiStateMachine: Leaving Connected state");
6956            if (mWifiConnectivityManager != null) {
6957                mWifiConnectivityManager.handleConnectionStateChanged(
6958                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
6959            }
6960
6961            mLastDriverRoamAttempt = 0;
6962            mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
6963        }
6964    }
6965
6966    class DisconnectingState extends State {
6967
6968        @Override
6969        public void enter() {
6970
6971            if (mVerboseLoggingEnabled) {
6972                logd(" Enter DisconnectingState State screenOn=" + mScreenOn);
6973            }
6974
6975            // Make sure we disconnect: we enter this state prior to connecting to a new
6976            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
6977            // event which in this case will be indicating that supplicant started to associate.
6978            // In some cases supplicant doesn't ignore the connect requests (it might not
6979            // find the target SSID in its cache),
6980            // Therefore we end up stuck that state, hence the need for the watchdog.
6981            disconnectingWatchdogCount++;
6982            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
6983            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
6984                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
6985        }
6986
6987        @Override
6988        public boolean processMessage(Message message) {
6989            logStateAndMessage(message, this);
6990            switch (message.what) {
6991                case CMD_SET_OPERATIONAL_MODE:
6992                    if (message.arg1 != CONNECT_MODE) {
6993                        deferMessage(message);
6994                    }
6995                    break;
6996                case CMD_START_SCAN:
6997                    deferMessage(message);
6998                    return HANDLED;
6999                case CMD_DISCONNECT:
7000                    if (mVerboseLoggingEnabled) log("Ignore CMD_DISCONNECT when already disconnecting.");
7001                    break;
7002                case CMD_DISCONNECTING_WATCHDOG_TIMER:
7003                    if (disconnectingWatchdogCount == message.arg1) {
7004                        if (mVerboseLoggingEnabled) log("disconnecting watchdog! -> disconnect");
7005                        handleNetworkDisconnect();
7006                        transitionTo(mDisconnectedState);
7007                    }
7008                    break;
7009                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7010                    /**
7011                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
7012                     * we have missed the network disconnection, transition to mDisconnectedState
7013                     * and handle the rest of the events there
7014                     */
7015                    deferMessage(message);
7016                    handleNetworkDisconnect();
7017                    transitionTo(mDisconnectedState);
7018                    break;
7019                default:
7020                    return NOT_HANDLED;
7021            }
7022            return HANDLED;
7023        }
7024    }
7025
7026    class DisconnectedState extends State {
7027        @Override
7028        public void enter() {
7029            // We dont scan frequently if this is a temporary disconnect
7030            // due to p2p
7031            if (mTemporarilyDisconnectWifi) {
7032                p2pSendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
7033                return;
7034            }
7035
7036            if (mVerboseLoggingEnabled) {
7037                logd(" Enter DisconnectedState screenOn=" + mScreenOn);
7038            }
7039
7040            /** clear the roaming state, if we were roaming, we failed */
7041            mAutoRoaming = false;
7042
7043            if (mWifiConnectivityManager != null) {
7044                mWifiConnectivityManager.handleConnectionStateChanged(
7045                        WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
7046            }
7047
7048            /**
7049             * If we have no networks saved, the supplicant stops doing the periodic scan.
7050             * The scans are useful to notify the user of the presence of an open network.
7051             * Note that these are not wake up scans.
7052             */
7053            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
7054                    && mWifiConfigManager.getSavedNetworks().size() == 0) {
7055                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7056                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7057            }
7058
7059            mDisconnectedTimeStamp = mClock.getWallClockMillis();
7060        }
7061        @Override
7062        public boolean processMessage(Message message) {
7063            boolean ret = HANDLED;
7064
7065            logStateAndMessage(message, this);
7066
7067            switch (message.what) {
7068                case CMD_NO_NETWORKS_PERIODIC_SCAN:
7069                    if (mP2pConnected.get()) break;
7070                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
7071                            mWifiConfigManager.getSavedNetworks().size() == 0) {
7072                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, WIFI_WORK_SOURCE);
7073                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7074                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7075                    }
7076                    break;
7077                case WifiManager.FORGET_NETWORK:
7078                case CMD_REMOVE_NETWORK:
7079                case CMD_REMOVE_APP_CONFIGURATIONS:
7080                case CMD_REMOVE_USER_CONFIGURATIONS:
7081                    // Set up a delayed message here. After the forget/remove is handled
7082                    // the handled delayed message will determine if there is a need to
7083                    // scan and continue
7084                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7085                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7086                    ret = NOT_HANDLED;
7087                    break;
7088                case CMD_SET_OPERATIONAL_MODE:
7089                    if (message.arg1 != CONNECT_MODE) {
7090                        mOperationalMode = message.arg1;
7091                        mWifiConfigManager.disableAllNetworksNative();
7092                        if (mOperationalMode == DISABLED_MODE) {
7093                            transitionTo(mSupplicantStoppingState);
7094                        } else if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
7095                            p2pSendMessage(CMD_DISABLE_P2P_REQ);
7096                            setWifiState(WIFI_STATE_DISABLED);
7097                            transitionTo(mScanModeState);
7098                        } else if (mOperationalMode == SCAN_ONLY_MODE) {
7099                            transitionTo(mScanModeState);
7100                        }
7101                    }
7102                    mWifiConfigManager.
7103                            setAndEnableLastSelectedConfiguration(
7104                                    WifiConfiguration.INVALID_NETWORK_ID);
7105                    break;
7106                case CMD_DISCONNECT:
7107                    if (mVerboseLoggingEnabled) log("Ignore CMD_DISCONNECT when already disconnected.");
7108                    break;
7109                /* Ignore network disconnect */
7110                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7111                    // Interpret this as an L2 connection failure
7112                    break;
7113                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7114                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7115                    if (mVerboseLoggingEnabled) {
7116                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
7117                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
7118                                + " debouncing=" + isLinkDebouncing());
7119                    }
7120                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
7121                    /* ConnectModeState does the rest of the handling */
7122                    ret = NOT_HANDLED;
7123                    break;
7124                case CMD_START_SCAN:
7125                    if (!checkOrDeferScanAllowed(message)) {
7126                        // The scan request was rescheduled
7127                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
7128                        return HANDLED;
7129                    }
7130
7131                    ret = NOT_HANDLED;
7132                    break;
7133                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
7134                    NetworkInfo info = (NetworkInfo) message.obj;
7135                    mP2pConnected.set(info.isConnected());
7136                    if (mP2pConnected.get()) {
7137                        int defaultInterval = mContext.getResources().getInteger(
7138                                R.integer.config_wifi_scan_interval_p2p_connected);
7139                        long scanIntervalMs = mFacade.getLongSetting(mContext,
7140                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
7141                                defaultInterval);
7142                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
7143                    } else if (mWifiConfigManager.getSavedNetworks().size() == 0) {
7144                        if (mVerboseLoggingEnabled) log("Turn on scanning after p2p disconnected");
7145                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
7146                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
7147                    }
7148                    break;
7149                case CMD_RECONNECT:
7150                case CMD_REASSOCIATE:
7151                    if (mTemporarilyDisconnectWifi) {
7152                        // Drop a third party reconnect/reassociate if STA is
7153                        // temporarily disconnected for p2p
7154                        break;
7155                    } else {
7156                        // ConnectModeState handles it
7157                        ret = NOT_HANDLED;
7158                    }
7159                    break;
7160                case CMD_SCREEN_STATE_CHANGED:
7161                    handleScreenStateChanged(message.arg1 != 0);
7162                    break;
7163                default:
7164                    ret = NOT_HANDLED;
7165            }
7166            return ret;
7167        }
7168
7169        @Override
7170        public void exit() {
7171            if (mWifiConnectivityManager != null) {
7172                mWifiConnectivityManager.handleConnectionStateChanged(
7173                         WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
7174            }
7175        }
7176    }
7177
7178    class WpsRunningState extends State {
7179        // Tracks the source to provide a reply
7180        private Message mSourceMessage;
7181        @Override
7182        public void enter() {
7183            mSourceMessage = Message.obtain(getCurrentMessage());
7184        }
7185        @Override
7186        public boolean processMessage(Message message) {
7187            logStateAndMessage(message, this);
7188
7189            switch (message.what) {
7190                case WifiMonitor.WPS_SUCCESS_EVENT:
7191                    // Ignore intermediate success, wait for full connection
7192                    break;
7193                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7194                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
7195                    mSourceMessage.recycle();
7196                    mSourceMessage = null;
7197                    deferMessage(message);
7198                    transitionTo(mDisconnectedState);
7199                    break;
7200                case WifiMonitor.WPS_OVERLAP_EVENT:
7201                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7202                            WifiManager.WPS_OVERLAP_ERROR);
7203                    mSourceMessage.recycle();
7204                    mSourceMessage = null;
7205                    transitionTo(mDisconnectedState);
7206                    break;
7207                case WifiMonitor.WPS_FAIL_EVENT:
7208                    // Arg1 has the reason for the failure
7209                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
7210                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
7211                        mSourceMessage.recycle();
7212                        mSourceMessage = null;
7213                        transitionTo(mDisconnectedState);
7214                    } else {
7215                        if (mVerboseLoggingEnabled) {
7216                            log("Ignore unspecified fail event during WPS connection");
7217                        }
7218                    }
7219                    break;
7220                case WifiMonitor.WPS_TIMEOUT_EVENT:
7221                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
7222                            WifiManager.WPS_TIMED_OUT);
7223                    mSourceMessage.recycle();
7224                    mSourceMessage = null;
7225                    transitionTo(mDisconnectedState);
7226                    break;
7227                case WifiManager.START_WPS:
7228                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
7229                    break;
7230                case WifiManager.CANCEL_WPS:
7231                    if (mWifiNative.cancelWps()) {
7232                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
7233                    } else {
7234                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
7235                    }
7236                    transitionTo(mDisconnectedState);
7237                    break;
7238                /**
7239                 * Defer all commands that can cause connections to a different network
7240                 * or put the state machine out of connect mode
7241                 */
7242                case CMD_SET_OPERATIONAL_MODE:
7243                case WifiManager.CONNECT_NETWORK:
7244                case CMD_ENABLE_NETWORK:
7245                case CMD_RECONNECT:
7246                case CMD_REASSOCIATE:
7247                case CMD_ENABLE_ALL_NETWORKS:
7248                    deferMessage(message);
7249                    break;
7250                case CMD_AUTO_CONNECT:
7251                case CMD_AUTO_ROAM:
7252                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7253                    return HANDLED;
7254                case CMD_START_SCAN:
7255                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7256                    return HANDLED;
7257                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7258                    if (mVerboseLoggingEnabled) log("Network connection lost");
7259                    handleNetworkDisconnect();
7260                    break;
7261                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
7262                    if (mVerboseLoggingEnabled) {
7263                        log("Ignore Assoc reject event during WPS Connection");
7264                    }
7265                    break;
7266                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
7267                    // Disregard auth failure events during WPS connection. The
7268                    // EAP sequence is retried several times, and there might be
7269                    // failures (especially for wps pin). We will get a WPS_XXX
7270                    // event at the end of the sequence anyway.
7271                    if (mVerboseLoggingEnabled) log("Ignore auth failure during WPS connection");
7272                    break;
7273                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7274                    // Throw away supplicant state changes when WPS is running.
7275                    // We will start getting supplicant state changes once we get
7276                    // a WPS success or failure
7277                    break;
7278                default:
7279                    return NOT_HANDLED;
7280            }
7281            return HANDLED;
7282        }
7283
7284        @Override
7285        public void exit() {
7286            mWifiConfigManager.enableAllNetworks();
7287            mWifiConfigManager.loadConfiguredNetworks();
7288        }
7289    }
7290
7291    class SoftApState extends State {
7292        private SoftApManager mSoftApManager;
7293
7294        private class SoftApListener implements SoftApManager.Listener {
7295            @Override
7296            public void onStateChanged(int state, int reason) {
7297                if (state == WIFI_AP_STATE_DISABLED) {
7298                    sendMessage(CMD_AP_STOPPED);
7299                } else if (state == WIFI_AP_STATE_FAILED) {
7300                    sendMessage(CMD_START_AP_FAILURE);
7301                }
7302
7303                setWifiApState(state, reason);
7304            }
7305        }
7306
7307        @Override
7308        public void enter() {
7309            final Message message = getCurrentMessage();
7310            if (message.what != CMD_START_AP) {
7311                throw new RuntimeException("Illegal transition to SoftApState: " + message);
7312            }
7313
7314            IApInterface apInterface = setupDriverForSoftAp();
7315            if (apInterface == null) {
7316                setWifiApState(WIFI_AP_STATE_FAILED,
7317                        WifiManager.SAP_START_FAILURE_GENERAL);
7318                /**
7319                 * Transition to InitialState to reset the
7320                 * driver/HAL back to the initial state.
7321                 */
7322                transitionTo(mInitialState);
7323                return;
7324            }
7325
7326            WifiConfiguration config = (WifiConfiguration) message.obj;
7327            if (config == null) {
7328                /**
7329                 * Configuration not provided in the command, fallback to use the current
7330                 * configuration.
7331                 */
7332                config = mWifiApConfigStore.getApConfiguration();
7333            } else {
7334                /* Update AP configuration. */
7335                mWifiApConfigStore.setApConfiguration(config);
7336            }
7337
7338            checkAndSetConnectivityInstance();
7339            mSoftApManager = mWifiInjector.makeSoftApManager(
7340                    mWifiNative, mNwService,
7341                    mCm, mCountryCode.getCountryCode(),
7342                    mWifiApConfigStore.getAllowed2GChannel(),
7343                    new SoftApListener(), apInterface);
7344            mSoftApManager.start(config);
7345        }
7346
7347        @Override
7348        public void exit() {
7349            mSoftApManager = null;
7350        }
7351
7352        @Override
7353        public boolean processMessage(Message message) {
7354            logStateAndMessage(message, this);
7355
7356            switch(message.what) {
7357                case CMD_START_AP:
7358                    /* Ignore start command when it is starting/started. */
7359                    break;
7360                case CMD_STOP_AP:
7361                    mSoftApManager.stop();
7362                    break;
7363                case CMD_START_AP_FAILURE:
7364                    transitionTo(mInitialState);
7365                    break;
7366                case CMD_AP_STOPPED:
7367                    transitionTo(mInitialState);
7368                    break;
7369                default:
7370                    return NOT_HANDLED;
7371            }
7372            return HANDLED;
7373        }
7374    }
7375
7376    /**
7377     * State machine initiated requests can have replyTo set to null indicating
7378     * there are no recepients, we ignore those reply actions.
7379     */
7380    private void replyToMessage(Message msg, int what) {
7381        if (msg.replyTo == null) return;
7382        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7383        mReplyChannel.replyToMessage(msg, dstMsg);
7384    }
7385
7386    private void replyToMessage(Message msg, int what, int arg1) {
7387        if (msg.replyTo == null) return;
7388        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7389        dstMsg.arg1 = arg1;
7390        mReplyChannel.replyToMessage(msg, dstMsg);
7391    }
7392
7393    private void replyToMessage(Message msg, int what, Object obj) {
7394        if (msg.replyTo == null) return;
7395        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
7396        dstMsg.obj = obj;
7397        mReplyChannel.replyToMessage(msg, dstMsg);
7398    }
7399
7400    /**
7401     * arg2 on the source message has a unique id that needs to be retained in replies
7402     * to match the request
7403     * <p>see WifiManager for details
7404     */
7405    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
7406        Message msg = Message.obtain();
7407        msg.what = what;
7408        msg.arg2 = srcMsg.arg2;
7409        return msg;
7410    }
7411
7412    /**
7413     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
7414     * @param config Must have a WifiConfiguration object to succeed
7415     */
7416    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
7417            WifiConfiguration config) {
7418        if (config != null && config.preSharedKey != null) {
7419            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
7420            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
7421            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
7422                    wifiCredentialEventType);
7423            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
7424                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
7425        }
7426    }
7427
7428    void handleGsmAuthRequest(SimAuthRequestData requestData) {
7429        if (targetWificonfiguration == null
7430                || targetWificonfiguration.networkId == requestData.networkId) {
7431            logd("id matches targetWifiConfiguration");
7432        } else {
7433            logd("id does not match targetWifiConfiguration");
7434            return;
7435        }
7436
7437        String response =
7438                TelephonyUtil.getGsmSimAuthResponse(requestData.data, getTelephonyManager());
7439        if (response == null) {
7440            mWifiNative.simAuthFailedResponse(requestData.networkId);
7441        } else {
7442            logv("Supplicant Response -" + response);
7443            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
7444        }
7445    }
7446
7447    void handle3GAuthRequest(SimAuthRequestData requestData) {
7448        if (targetWificonfiguration == null
7449                || targetWificonfiguration.networkId == requestData.networkId) {
7450            logd("id matches targetWifiConfiguration");
7451        } else {
7452            logd("id does not match targetWifiConfiguration");
7453            return;
7454        }
7455
7456        SimAuthResponseData response =
7457                TelephonyUtil.get3GAuthResponse(requestData, getTelephonyManager());
7458        if (response != null) {
7459            mWifiNative.simAuthResponse(requestData.networkId, response.type, response.response);
7460        } else {
7461            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
7462        }
7463    }
7464
7465    /**
7466     * Automatically connect to the network specified
7467     *
7468     * @param networkId ID of the network to connect to
7469     * @param bssid BSSID of the network
7470     */
7471    public void autoConnectToNetwork(int networkId, String bssid) {
7472        sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);
7473    }
7474
7475    /**
7476     * Automatically roam to the network specified
7477     *
7478     * @param networkId ID of the network to roam to
7479     * @param scanResult scan result which identifies the network to roam to
7480     */
7481    public void autoRoamToNetwork(int networkId, ScanResult scanResult) {
7482        sendMessage(CMD_AUTO_ROAM, networkId, 0, scanResult);
7483    }
7484
7485    /**
7486     * Dynamically turn on/off WifiConnectivityManager
7487     *
7488     * @param enabled true-enable; false-disable
7489     */
7490    public void enableWifiConnectivityManager(boolean enabled) {
7491        sendMessage(CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER, enabled ? 1 : 0);
7492    }
7493
7494    /**
7495     * @param reason reason code from supplicant on network disconnected event
7496     * @return true if this is a suspicious disconnect
7497     */
7498    static boolean unexpectedDisconnectedReason(int reason) {
7499        return reason == 2              // PREV_AUTH_NOT_VALID
7500                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
7501                || reason == 7          // FRAME_FROM_NONASSOC_STA
7502                || reason == 8          // STA_HAS_LEFT
7503                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
7504                || reason == 14         // MICHAEL_MIC_FAILURE
7505                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
7506                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
7507                || reason == 18         // GROUP_CIPHER_NOT_VALID
7508                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
7509                || reason == 23         // IEEE_802_1X_AUTH_FAILED
7510                || reason == 34;        // DISASSOC_LOW_ACK
7511    }
7512
7513    /**
7514     * Update WifiMetrics before dumping
7515     */
7516    void updateWifiMetrics() {
7517        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworksSize();
7518        int numOpenNetworks = 0;
7519        int numPersonalNetworks = 0;
7520        int numEnterpriseNetworks = 0;
7521        int numNetworksAddedByUser = 0;
7522        int numNetworksAddedByApps = 0;
7523        for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) {
7524            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
7525                numOpenNetworks++;
7526            } else if (config.isEnterprise()) {
7527                numEnterpriseNetworks++;
7528            } else {
7529                numPersonalNetworks++;
7530            }
7531            if (config.selfAdded) {
7532                numNetworksAddedByUser++;
7533            } else {
7534                numNetworksAddedByApps++;
7535            }
7536        }
7537        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
7538        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
7539        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
7540        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
7541        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
7542        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
7543
7544        /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually
7545        mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt(
7546                mContext.getContentResolver(),
7547                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
7548                != Settings.Secure.LOCATION_MODE_OFF);
7549                */
7550
7551        /* <TODO> decide how statemachine will access WifiSettingsStore
7552        mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable());
7553         */
7554    }
7555
7556    private static String getLinkPropertiesSummary(LinkProperties lp) {
7557        List<String> attributes = new ArrayList<>(6);
7558        if (lp.hasIPv4Address()) {
7559            attributes.add("v4");
7560        }
7561        if (lp.hasIPv4DefaultRoute()) {
7562            attributes.add("v4r");
7563        }
7564        if (lp.hasIPv4DnsServer()) {
7565            attributes.add("v4dns");
7566        }
7567        if (lp.hasGlobalIPv6Address()) {
7568            attributes.add("v6");
7569        }
7570        if (lp.hasIPv6DefaultRoute()) {
7571            attributes.add("v6r");
7572        }
7573        if (lp.hasIPv6DnsServer()) {
7574            attributes.add("v6dns");
7575        }
7576
7577        return TextUtils.join(" ", attributes);
7578    }
7579
7580    private void wnmFrameReceived(WnmData event) {
7581        // %012x HS20-SUBSCRIPTION-REMEDIATION "%u %s", osu_method, url
7582        // %012x HS20-DEAUTH-IMMINENT-NOTICE "%u %u %s", code, reauth_delay, url
7583
7584        Intent intent = new Intent(WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION);
7585        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
7586
7587        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_BSSID, event.getBssid());
7588        intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_URL, event.getUrl());
7589
7590        if (event.isDeauthEvent()) {
7591            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_ESS, event.isEss());
7592            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_DELAY, event.getDelay());
7593        } else {
7594            intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_METHOD, event.getMethod());
7595            WifiConfiguration config = getCurrentWifiConfiguration();
7596            if (config != null && config.FQDN != null) {
7597                intent.putExtra(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH,
7598                        mWifiConfigManager.matchProviderWithCurrentNetwork(config.FQDN));
7599            }
7600        }
7601        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
7602    }
7603
7604    /**
7605     * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
7606     * This should match the network config framework is attempting to connect to.
7607     */
7608    private String getTargetSsid() {
7609        WifiConfiguration currentConfig = mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
7610        if (currentConfig != null) {
7611            return currentConfig.SSID;
7612        }
7613        return null;
7614    }
7615
7616    private void p2pSendMessage(int what) {
7617        if (mWifiP2pChannel != null) {
7618            mWifiP2pChannel.sendMessage(what);
7619        }
7620    }
7621
7622    private void p2pSendMessage(int what, int arg1) {
7623        if (mWifiP2pChannel != null) {
7624            mWifiP2pChannel.sendMessage(what, arg1);
7625        }
7626    }
7627}
7628