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