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