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