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