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