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