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