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