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