WifiStateMachine.java revision b740903bec94d63f89904ec9561085f9ca6c453a
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                case CMD_RESET_SIM_NETWORKS:
5110                    /* Defer this message until supplicant is started. */
5111                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5112                    deferMessage(message);
5113                    break;
5114                default:
5115                    loge("Error! unhandled message" + message);
5116                    break;
5117            }
5118            return HANDLED;
5119        }
5120    }
5121
5122    class InitialState extends State {
5123        @Override
5124        public void enter() {
5125            mWifiNative.stopHal();
5126            mWifiNative.unloadDriver();
5127            if (mWifiP2pChannel == null) {
5128                mWifiP2pChannel = new AsyncChannel();
5129                mWifiP2pChannel.connect(mContext, getHandler(),
5130                    mWifiP2pServiceImpl.getP2pStateMachineMessenger());
5131            }
5132
5133            if (mWifiApConfigStore == null) {
5134                mWifiApConfigStore =
5135                        mFacade.makeApConfigStore(mContext, mBackupManagerProxy);
5136            }
5137
5138            if (mWifiConfigManager.enableHalBasedPno.get()) {
5139                // make sure developer Settings are in sync with the config option
5140                mHalBasedPnoEnableInDevSettings = true;
5141            }
5142        }
5143        @Override
5144        public boolean processMessage(Message message) {
5145            logStateAndMessage(message, this);
5146            switch (message.what) {
5147                case CMD_START_SUPPLICANT:
5148                    if (mWifiNative.loadDriver()) {
5149                        try {
5150                            mNwService.wifiFirmwareReload(mInterfaceName, "STA");
5151                        } catch (Exception e) {
5152                            loge("Failed to reload STA firmware " + e);
5153                            // Continue
5154                        }
5155
5156                        try {
5157                            // A runtime crash can leave the interface up and
5158                            // IP addresses configured, and this affects
5159                            // connectivity when supplicant starts up.
5160                            // Ensure interface is down and we have no IP
5161                            // addresses before a supplicant start.
5162                            mNwService.setInterfaceDown(mInterfaceName);
5163                            mNwService.clearInterfaceAddresses(mInterfaceName);
5164
5165                            // Set privacy extensions
5166                            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
5167
5168                            // IPv6 is enabled only as long as access point is connected since:
5169                            // - IPv6 addresses and routes stick around after disconnection
5170                            // - kernel is unaware when connected and fails to start IPv6 negotiation
5171                            // - kernel can start autoconfiguration when 802.1x is not complete
5172                            mNwService.disableIpv6(mInterfaceName);
5173                        } catch (RemoteException re) {
5174                            loge("Unable to change interface settings: " + re);
5175                        } catch (IllegalStateException ie) {
5176                            loge("Unable to change interface settings: " + ie);
5177                        }
5178
5179                       /* Stop a running supplicant after a runtime restart
5180                        * Avoids issues with drivers that do not handle interface down
5181                        * on a running supplicant properly.
5182                        */
5183                        mWifiMonitor.killSupplicant(mP2pSupported);
5184
5185                        if (mWifiNative.startHal() == false) {
5186                            /* starting HAL is optional */
5187                            loge("Failed to start HAL");
5188                        }
5189
5190                        if (mWifiNative.startSupplicant(mP2pSupported)) {
5191                            setWifiState(WIFI_STATE_ENABLING);
5192                            if (DBG) log("Supplicant start successful");
5193                            mWifiMonitor.startMonitoring(mInterfaceName);
5194                            transitionTo(mSupplicantStartingState);
5195                        } else {
5196                            loge("Failed to start supplicant!");
5197                        }
5198                    } else {
5199                        loge("Failed to load driver");
5200                    }
5201                    break;
5202                case CMD_START_AP:
5203                    if (setupDriverForSoftAp()) {
5204                        transitionTo(mSoftApState);
5205                    } else {
5206                        setWifiApState(WIFI_AP_STATE_FAILED,
5207                                WifiManager.SAP_START_FAILURE_GENERAL);
5208                        /**
5209                         * Transition to InitialState (current state) to reset the
5210                         * driver/HAL back to the initial state.
5211                         */
5212                        transitionTo(mInitialState);
5213                    }
5214                    break;
5215                default:
5216                    return NOT_HANDLED;
5217            }
5218            return HANDLED;
5219        }
5220    }
5221
5222    class SupplicantStartingState extends State {
5223        private void initializeWpsDetails() {
5224            String detail;
5225            detail = SystemProperties.get("ro.product.name", "");
5226            if (!mWifiNative.setDeviceName(detail)) {
5227                loge("Failed to set device name " +  detail);
5228            }
5229            detail = SystemProperties.get("ro.product.manufacturer", "");
5230            if (!mWifiNative.setManufacturer(detail)) {
5231                loge("Failed to set manufacturer " + detail);
5232            }
5233            detail = SystemProperties.get("ro.product.model", "");
5234            if (!mWifiNative.setModelName(detail)) {
5235                loge("Failed to set model name " + detail);
5236            }
5237            detail = SystemProperties.get("ro.product.model", "");
5238            if (!mWifiNative.setModelNumber(detail)) {
5239                loge("Failed to set model number " + detail);
5240            }
5241            detail = SystemProperties.get("ro.serialno", "");
5242            if (!mWifiNative.setSerialNumber(detail)) {
5243                loge("Failed to set serial number " + detail);
5244            }
5245            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
5246                loge("Failed to set WPS config methods");
5247            }
5248            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
5249                loge("Failed to set primary device type " + mPrimaryDeviceType);
5250            }
5251        }
5252
5253        @Override
5254        public boolean processMessage(Message message) {
5255            logStateAndMessage(message, this);
5256
5257            switch(message.what) {
5258                case WifiMonitor.SUP_CONNECTION_EVENT:
5259                    if (DBG) log("Supplicant connection established");
5260                    setWifiState(WIFI_STATE_ENABLED);
5261                    mSupplicantRestartCount = 0;
5262                    /* Reset the supplicant state to indicate the supplicant
5263                     * state is not known at this time */
5264                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5265                    /* Initialize data structures */
5266                    mLastBssid = null;
5267                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
5268                    mLastSignalLevel = -1;
5269
5270                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
5271                    /* set frequency band of operation */
5272                    setFrequencyBand();
5273                    mWifiNative.enableSaveConfig();
5274                    mWifiConfigManager.loadAndEnableAllNetworks();
5275                    if (mWifiConfigManager.enableVerboseLogging.get() > 0) {
5276                        enableVerboseLogging(mWifiConfigManager.enableVerboseLogging.get());
5277                    }
5278                    initializeWpsDetails();
5279
5280                    sendSupplicantConnectionChangedBroadcast(true);
5281                    transitionTo(mDriverStartedState);
5282                    break;
5283                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5284                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
5285                        loge("Failed to setup control channel, restart supplicant");
5286                        mWifiMonitor.killSupplicant(mP2pSupported);
5287                        transitionTo(mInitialState);
5288                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5289                    } else {
5290                        loge("Failed " + mSupplicantRestartCount +
5291                                " times to start supplicant, unload driver");
5292                        mSupplicantRestartCount = 0;
5293                        setWifiState(WIFI_STATE_UNKNOWN);
5294                        transitionTo(mInitialState);
5295                    }
5296                    break;
5297                case CMD_START_SUPPLICANT:
5298                case CMD_STOP_SUPPLICANT:
5299                case CMD_START_AP:
5300                case CMD_STOP_AP:
5301                case CMD_START_DRIVER:
5302                case CMD_STOP_DRIVER:
5303                case CMD_SET_OPERATIONAL_MODE:
5304                case CMD_SET_COUNTRY_CODE:
5305                case CMD_SET_FREQUENCY_BAND:
5306                case CMD_START_PACKET_FILTERING:
5307                case CMD_STOP_PACKET_FILTERING:
5308                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5309                    deferMessage(message);
5310                    break;
5311                default:
5312                    return NOT_HANDLED;
5313            }
5314            return HANDLED;
5315        }
5316    }
5317
5318    class SupplicantStartedState extends State {
5319        @Override
5320        public void enter() {
5321            /* Wifi is available as long as we have a connection to supplicant */
5322            mNetworkInfo.setIsAvailable(true);
5323            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5324
5325            int defaultInterval = mContext.getResources().getInteger(
5326                    R.integer.config_wifi_supplicant_scan_interval);
5327
5328            mSupplicantScanIntervalMs = mFacade.getLongSetting(mContext,
5329                    Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
5330                    defaultInterval);
5331
5332            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
5333            mWifiNative.setExternalSim(true);
5334
5335            /* turn on use of DFS channels */
5336            mWifiNative.setDfsFlag(true);
5337
5338            /* set country code */
5339            initializeCountryCode();
5340
5341            setRandomMacOui();
5342            mWifiNative.enableAutoConnect(false);
5343        }
5344
5345        @Override
5346        public boolean processMessage(Message message) {
5347            logStateAndMessage(message, this);
5348
5349            switch(message.what) {
5350                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
5351                    if (mP2pSupported) {
5352                        transitionTo(mWaitForP2pDisableState);
5353                    } else {
5354                        transitionTo(mSupplicantStoppingState);
5355                    }
5356                    break;
5357                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
5358                    loge("Connection lost, restart supplicant");
5359                    handleSupplicantConnectionLoss(true);
5360                    handleNetworkDisconnect();
5361                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5362                    if (mP2pSupported) {
5363                        transitionTo(mWaitForP2pDisableState);
5364                    } else {
5365                        transitionTo(mInitialState);
5366                    }
5367                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5368                    break;
5369                case WifiMonitor.SCAN_RESULTS_EVENT:
5370                case WifiMonitor.SCAN_FAILED_EVENT:
5371                    maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
5372                    noteScanEnd();
5373                    setScanResults();
5374                    if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
5375                        /* Just updated results from full scan, let apps know about this */
5376                        boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
5377                        sendScanResultsAvailableBroadcast(scanSucceeded);
5378                    }
5379                    mSendScanResultsBroadcast = false;
5380                    mIsScanOngoing = false;
5381                    mIsFullScanOngoing = false;
5382                    if (mBufferedScanMsg.size() > 0)
5383                        sendMessage(mBufferedScanMsg.remove());
5384                    break;
5385                case CMD_PING_SUPPLICANT:
5386                    boolean ok = mWifiNative.ping();
5387                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5388                    break;
5389                case CMD_GET_CAPABILITY_FREQ:
5390                    String freqs = mWifiNative.getFreqCapability();
5391                    replyToMessage(message, message.what, freqs);
5392                    break;
5393                case CMD_START_AP:
5394                    /* Cannot start soft AP while in client mode */
5395                    loge("Failed to start soft AP with a running supplicant");
5396                    setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
5397                    break;
5398                case CMD_SET_OPERATIONAL_MODE:
5399                    mOperationalMode = message.arg1;
5400                    mWifiConfigManager.
5401                            setAndEnableLastSelectedConfiguration(
5402                                    WifiConfiguration.INVALID_NETWORK_ID);
5403                    break;
5404                case CMD_TARGET_BSSID:
5405                    // Trying to associate to this BSSID
5406                    if (message.obj != null) {
5407                        mTargetRoamBSSID = (String) message.obj;
5408                    }
5409                    break;
5410                case CMD_GET_LINK_LAYER_STATS:
5411                    WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
5412                    if (stats == null) {
5413                        // When firmware doesnt support link layer stats, return an empty object
5414                        stats = new WifiLinkLayerStats();
5415                    }
5416                    replyToMessage(message, message.what, stats);
5417                    break;
5418                case CMD_SET_COUNTRY_CODE:
5419                    String country = (String) message.obj;
5420                    final boolean persist = (message.arg2 == 1);
5421                    final int sequence = message.arg1;
5422                    if (sequence != mCountryCodeSequence.get()) {
5423                        if (DBG) log("set country code ignored due to sequnce num");
5424                        break;
5425                    }
5426
5427                    country = country.toUpperCase(Locale.ROOT);
5428
5429                    if (DBG) log("set country code " + (country == null ? "(null)" : country));
5430
5431                    if (!TextUtils.equals(mDriverSetCountryCode, country)) {
5432                        if (mWifiNative.setCountryCode(country)) {
5433                            mDriverSetCountryCode = country;
5434                            mHasSetCountryCode.set(true);
5435                            if (persist) {
5436                                Settings.Global.putString(mContext.getContentResolver(),
5437                                        Settings.Global.WIFI_COUNTRY_CODE,
5438                                        country == null ? "" : country);
5439                            }
5440                        } else {
5441                            loge("Failed to set country code " + country);
5442                        }
5443                    }
5444
5445                    mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country);
5446                    break;
5447                case CMD_RESET_SIM_NETWORKS:
5448                    log("resetting EAP-SIM/AKA/AKA' networks since SIM was removed");
5449                    mWifiConfigManager.resetSimNetworks();
5450                    break;
5451                default:
5452                    return NOT_HANDLED;
5453            }
5454            return HANDLED;
5455        }
5456
5457        @Override
5458        public void exit() {
5459            mNetworkInfo.setIsAvailable(false);
5460            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5461        }
5462    }
5463
5464    class SupplicantStoppingState extends State {
5465        @Override
5466        public void enter() {
5467            /* Send any reset commands to supplicant before shutting it down */
5468            handleNetworkDisconnect();
5469
5470            String suppState = System.getProperty("init.svc.wpa_supplicant");
5471            if (suppState == null) suppState = "unknown";
5472            String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");
5473            if (p2pSuppState == null) p2pSuppState = "unknown";
5474
5475            logd("SupplicantStoppingState: stopSupplicant "
5476                    + " init.svc.wpa_supplicant=" + suppState
5477                    + " init.svc.p2p_supplicant=" + p2pSuppState);
5478            mWifiMonitor.stopSupplicant();
5479
5480            /* Send ourselves a delayed message to indicate failure after a wait time */
5481            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
5482                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
5483            setWifiState(WIFI_STATE_DISABLING);
5484            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5485        }
5486        @Override
5487        public boolean processMessage(Message message) {
5488            logStateAndMessage(message, this);
5489
5490            switch(message.what) {
5491                case WifiMonitor.SUP_CONNECTION_EVENT:
5492                    loge("Supplicant connection received while stopping");
5493                    break;
5494                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5495                    if (DBG) log("Supplicant connection lost");
5496                    handleSupplicantConnectionLoss(false);
5497                    transitionTo(mInitialState);
5498                    break;
5499                case CMD_STOP_SUPPLICANT_FAILED:
5500                    if (message.arg1 == mSupplicantStopFailureToken) {
5501                        loge("Timed out on a supplicant stop, kill and proceed");
5502                        handleSupplicantConnectionLoss(true);
5503                        transitionTo(mInitialState);
5504                    }
5505                    break;
5506                case CMD_START_SUPPLICANT:
5507                case CMD_STOP_SUPPLICANT:
5508                case CMD_START_AP:
5509                case CMD_STOP_AP:
5510                case CMD_START_DRIVER:
5511                case CMD_STOP_DRIVER:
5512                case CMD_SET_OPERATIONAL_MODE:
5513                case CMD_SET_COUNTRY_CODE:
5514                case CMD_SET_FREQUENCY_BAND:
5515                case CMD_START_PACKET_FILTERING:
5516                case CMD_STOP_PACKET_FILTERING:
5517                    deferMessage(message);
5518                    break;
5519                default:
5520                    return NOT_HANDLED;
5521            }
5522            return HANDLED;
5523        }
5524    }
5525
5526    class DriverStartingState extends State {
5527        private int mTries;
5528        @Override
5529        public void enter() {
5530            mTries = 1;
5531            /* Send ourselves a delayed message to start driver a second time */
5532            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
5533                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
5534        }
5535        @Override
5536        public boolean processMessage(Message message) {
5537            logStateAndMessage(message, this);
5538
5539            switch(message.what) {
5540               case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5541                    SupplicantState state = handleSupplicantStateChange(message);
5542                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
5543                     * a state that indicates driver has started, it is ready to
5544                     * receive driver commands
5545                     */
5546                    if (SupplicantState.isDriverActive(state)) {
5547                        transitionTo(mDriverStartedState);
5548                    }
5549                    break;
5550                case CMD_DRIVER_START_TIMED_OUT:
5551                    if (message.arg1 == mDriverStartToken) {
5552                        if (mTries >= 2) {
5553                            loge("Failed to start driver after " + mTries);
5554                            setSupplicantRunning(false);
5555                            setSupplicantRunning(true);
5556                        } else {
5557                            loge("Driver start failed, retrying");
5558                            mWakeLock.acquire();
5559                            mWifiNative.startDriver();
5560                            mWakeLock.release();
5561
5562                            ++mTries;
5563                            /* Send ourselves a delayed message to start driver again */
5564                            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
5565                                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
5566                        }
5567                    }
5568                    break;
5569                    /* Queue driver commands & connection events */
5570                case CMD_START_DRIVER:
5571                case CMD_STOP_DRIVER:
5572                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5573                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5574                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5575                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5576                case WifiMonitor.WPS_OVERLAP_EVENT:
5577                case CMD_SET_COUNTRY_CODE:
5578                case CMD_SET_FREQUENCY_BAND:
5579                case CMD_START_PACKET_FILTERING:
5580                case CMD_STOP_PACKET_FILTERING:
5581                case CMD_START_SCAN:
5582                case CMD_DISCONNECT:
5583                case CMD_REASSOCIATE:
5584                case CMD_RECONNECT:
5585                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5586                    deferMessage(message);
5587                    break;
5588                case WifiMonitor.SCAN_RESULTS_EVENT:
5589                case WifiMonitor.SCAN_FAILED_EVENT:
5590                    // Loose scan results obtained in Driver Starting state, they can only confuse
5591                    // the state machine
5592                    break;
5593                default:
5594                    return NOT_HANDLED;
5595            }
5596            return HANDLED;
5597        }
5598    }
5599
5600    class DriverStartedState extends State {
5601        @Override
5602        public void enter() {
5603            if (DBG) {
5604                logd("DriverStartedState enter");
5605            }
5606
5607            // We can't do this in the constructor because WifiStateMachine is created before the
5608            // wifi scanning service is initialized
5609            if (mWifiScanner == null) {
5610                mWifiScanner =
5611                        (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
5612            }
5613
5614            mWifiLogger.startLogging(DBG);
5615            mIsRunning = true;
5616            updateBatteryWorkSource(null);
5617            /**
5618             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
5619             * When this mode is on, some of the low-level scan parameters used by the
5620             * driver are changed to reduce interference with bluetooth
5621             */
5622            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
5623            /* initialize network state */
5624            setNetworkDetailedState(DetailedState.DISCONNECTED);
5625
5626            /* Remove any filtering on Multicast v6 at start */
5627            mWifiNative.stopFilteringMulticastV6Packets();
5628
5629            /* Reset Multicast v4 filtering state */
5630            if (mFilteringMulticastV4Packets.get()) {
5631                mWifiNative.startFilteringMulticastV4Packets();
5632            } else {
5633                mWifiNative.stopFilteringMulticastV4Packets();
5634            }
5635
5636            if (mOperationalMode != CONNECT_MODE) {
5637                mWifiNative.disconnect();
5638                mWifiConfigManager.disableAllNetworksNative();
5639                if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
5640                    setWifiState(WIFI_STATE_DISABLED);
5641                }
5642                transitionTo(mScanModeState);
5643            } else {
5644
5645                // Status pulls in the current supplicant state and network connection state
5646                // events over the monitor connection. This helps framework sync up with
5647                // current supplicant state
5648                // TODO: actually check th supplicant status string and make sure the supplicant
5649                // is in disconnecte4d state.
5650                mWifiNative.status();
5651                // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
5652                transitionTo(mDisconnectedState);
5653                transitionTo(mDisconnectedState);
5654            }
5655
5656            // We may have missed screen update at boot
5657            if (mScreenBroadcastReceived.get() == false) {
5658                PowerManager powerManager = (PowerManager)mContext.getSystemService(
5659                        Context.POWER_SERVICE);
5660                handleScreenStateChanged(powerManager.isScreenOn());
5661            } else {
5662                // Set the right suspend mode settings
5663                mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
5664                        && mUserWantsSuspendOpt.get());
5665            }
5666            mWifiNative.setPowerSave(true);
5667
5668            if (mP2pSupported) {
5669                if (mOperationalMode == CONNECT_MODE) {
5670                    mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
5671                } else {
5672                    // P2P statemachine starts in disabled state, and is not enabled until
5673                    // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
5674                    // keep it disabled.
5675                }
5676            }
5677
5678            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
5679            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
5680            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
5681            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
5682
5683            mHalFeatureSet = mWifiNative.getSupportedFeatureSet();
5684            if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO)
5685                    == WifiManager.WIFI_FEATURE_HAL_EPNO) {
5686                mHalBasedPnoDriverSupported = true;
5687            }
5688
5689            // Enable link layer stats gathering
5690            mWifiNative.setWifiLinkLayerStats("wlan0", 1);
5691
5692            if (DBG) {
5693                logd("Driverstarted State enter done, epno=" + mHalBasedPnoDriverSupported
5694                     + " feature=" + mHalFeatureSet);
5695            }
5696        }
5697
5698        @Override
5699        public boolean processMessage(Message message) {
5700            logStateAndMessage(message, this);
5701
5702            switch(message.what) {
5703                case CMD_START_SCAN:
5704                    handleScanRequest(message);
5705                    break;
5706                case CMD_SET_FREQUENCY_BAND:
5707                    int band =  message.arg1;
5708                    if (DBG) log("set frequency band " + band);
5709                    if (mWifiNative.setBand(band)) {
5710
5711                        if (DBG)  logd("did set frequency band " + band);
5712
5713                        mFrequencyBand.set(band);
5714                        // Flush old data - like scan results
5715                        mWifiNative.bssFlush();
5716
5717                        if (DBG)  logd("done set frequency band " + band);
5718
5719                    } else {
5720                        loge("Failed to set frequency band " + band);
5721                    }
5722                    break;
5723                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
5724                    mBluetoothConnectionActive = (message.arg1 !=
5725                            BluetoothAdapter.STATE_DISCONNECTED);
5726                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
5727                    break;
5728                case CMD_STOP_DRIVER:
5729                    int mode = message.arg1;
5730
5731                    log("stop driver");
5732                    mWifiConfigManager.disableAllNetworksNative();
5733
5734                    if (getCurrentState() != mDisconnectedState) {
5735                        mWifiNative.disconnect();
5736                        handleNetworkDisconnect();
5737                    }
5738                    mWakeLock.acquire();
5739                    mWifiNative.stopDriver();
5740                    mWakeLock.release();
5741                    if (mP2pSupported) {
5742                        transitionTo(mWaitForP2pDisableState);
5743                    } else {
5744                        transitionTo(mDriverStoppingState);
5745                    }
5746                    break;
5747                case CMD_START_DRIVER:
5748                    if (mOperationalMode == CONNECT_MODE) {
5749                        mWifiConfigManager.enableAllNetworks();
5750                    }
5751                    break;
5752                case CMD_START_PACKET_FILTERING:
5753                    if (message.arg1 == MULTICAST_V6) {
5754                        mWifiNative.startFilteringMulticastV6Packets();
5755                    } else if (message.arg1 == MULTICAST_V4) {
5756                        mWifiNative.startFilteringMulticastV4Packets();
5757                    } else {
5758                        loge("Illegal arugments to CMD_START_PACKET_FILTERING");
5759                    }
5760                    break;
5761                case CMD_STOP_PACKET_FILTERING:
5762                    if (message.arg1 == MULTICAST_V6) {
5763                        mWifiNative.stopFilteringMulticastV6Packets();
5764                    } else if (message.arg1 == MULTICAST_V4) {
5765                        mWifiNative.stopFilteringMulticastV4Packets();
5766                    } else {
5767                        loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
5768                    }
5769                    break;
5770                case CMD_SET_SUSPEND_OPT_ENABLED:
5771                    if (message.arg1 == 1) {
5772                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
5773                        mSuspendWakeLock.release();
5774                    } else {
5775                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
5776                    }
5777                    break;
5778                case CMD_SET_HIGH_PERF_MODE:
5779                    if (message.arg1 == 1) {
5780                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
5781                    } else {
5782                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
5783                    }
5784                    break;
5785                case CMD_ENABLE_TDLS:
5786                    if (message.obj != null) {
5787                        String remoteAddress = (String) message.obj;
5788                        boolean enable = (message.arg1 == 1);
5789                        mWifiNative.startTdls(remoteAddress, enable);
5790                    }
5791                    break;
5792                case WifiMonitor.ANQP_DONE_EVENT:
5793                    mWifiConfigManager.notifyANQPDone((Long) message.obj, message.arg1 != 0);
5794                    break;
5795                case CMD_STOP_IP_PACKET_OFFLOAD: {
5796                    int slot = message.arg1;
5797                    int ret = stopWifiIPPacketOffload(slot);
5798                    if (mNetworkAgent != null) {
5799                        mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
5800                    }
5801                    break;
5802                }
5803                case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
5804                    mWifiConfigManager.notifyIconReceived((IconEvent) message.obj);
5805                    break;
5806                case WifiMonitor.HS20_REMEDIATION_EVENT:
5807                    mWifiConfigManager.wnmFrameReceived((WnmData) message.obj);
5808                    break;
5809                default:
5810                    return NOT_HANDLED;
5811            }
5812            return HANDLED;
5813        }
5814        @Override
5815        public void exit() {
5816
5817            mWifiLogger.stopLogging();
5818
5819            mIsRunning = false;
5820            updateBatteryWorkSource(null);
5821            mScanResults = new ArrayList<>();
5822
5823            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
5824            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
5825            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
5826            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
5827            noteScanEnd(); // wrap up any pending request.
5828            mBufferedScanMsg.clear();
5829        }
5830    }
5831
5832    class WaitForP2pDisableState extends State {
5833        private State mTransitionToState;
5834        @Override
5835        public void enter() {
5836            switch (getCurrentMessage().what) {
5837                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5838                    mTransitionToState = mInitialState;
5839                    break;
5840                case CMD_STOP_DRIVER:
5841                    mTransitionToState = mDriverStoppingState;
5842                    break;
5843                case CMD_STOP_SUPPLICANT:
5844                    mTransitionToState = mSupplicantStoppingState;
5845                    break;
5846                default:
5847                    mTransitionToState = mDriverStoppingState;
5848                    break;
5849            }
5850            mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
5851        }
5852        @Override
5853        public boolean processMessage(Message message) {
5854            logStateAndMessage(message, this);
5855
5856            switch(message.what) {
5857                case WifiStateMachine.CMD_DISABLE_P2P_RSP:
5858                    transitionTo(mTransitionToState);
5859                    break;
5860                /* Defer wifi start/shut and driver commands */
5861                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5862                case CMD_START_SUPPLICANT:
5863                case CMD_STOP_SUPPLICANT:
5864                case CMD_START_AP:
5865                case CMD_STOP_AP:
5866                case CMD_START_DRIVER:
5867                case CMD_STOP_DRIVER:
5868                case CMD_SET_OPERATIONAL_MODE:
5869                case CMD_SET_COUNTRY_CODE:
5870                case CMD_SET_FREQUENCY_BAND:
5871                case CMD_START_PACKET_FILTERING:
5872                case CMD_STOP_PACKET_FILTERING:
5873                case CMD_START_SCAN:
5874                case CMD_DISCONNECT:
5875                case CMD_REASSOCIATE:
5876                case CMD_RECONNECT:
5877                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5878                    deferMessage(message);
5879                    break;
5880                default:
5881                    return NOT_HANDLED;
5882            }
5883            return HANDLED;
5884        }
5885    }
5886
5887    class DriverStoppingState extends State {
5888        @Override
5889        public boolean processMessage(Message message) {
5890            logStateAndMessage(message, this);
5891
5892            switch(message.what) {
5893                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5894                    SupplicantState state = handleSupplicantStateChange(message);
5895                    if (state == SupplicantState.INTERFACE_DISABLED) {
5896                        transitionTo(mDriverStoppedState);
5897                    }
5898                    break;
5899                    /* Queue driver commands */
5900                case CMD_START_DRIVER:
5901                case CMD_STOP_DRIVER:
5902                case CMD_SET_COUNTRY_CODE:
5903                case CMD_SET_FREQUENCY_BAND:
5904                case CMD_START_PACKET_FILTERING:
5905                case CMD_STOP_PACKET_FILTERING:
5906                case CMD_START_SCAN:
5907                case CMD_DISCONNECT:
5908                case CMD_REASSOCIATE:
5909                case CMD_RECONNECT:
5910                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5911                    deferMessage(message);
5912                    break;
5913                default:
5914                    return NOT_HANDLED;
5915            }
5916            return HANDLED;
5917        }
5918    }
5919
5920    class DriverStoppedState extends State {
5921        @Override
5922        public boolean processMessage(Message message) {
5923            logStateAndMessage(message, this);
5924            switch (message.what) {
5925                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5926                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5927                    SupplicantState state = stateChangeResult.state;
5928                    // A WEXT bug means that we can be back to driver started state
5929                    // unexpectedly
5930                    if (SupplicantState.isDriverActive(state)) {
5931                        transitionTo(mDriverStartedState);
5932                    }
5933                    break;
5934                case CMD_START_DRIVER:
5935                    mWakeLock.acquire();
5936                    mWifiNative.startDriver();
5937                    mWakeLock.release();
5938                    transitionTo(mDriverStartingState);
5939                    break;
5940                default:
5941                    return NOT_HANDLED;
5942            }
5943            return HANDLED;
5944        }
5945    }
5946
5947    class ScanModeState extends State {
5948        private int mLastOperationMode;
5949        @Override
5950        public void enter() {
5951            mLastOperationMode = mOperationalMode;
5952        }
5953        @Override
5954        public boolean processMessage(Message message) {
5955            logStateAndMessage(message, this);
5956
5957            switch(message.what) {
5958                case CMD_SET_OPERATIONAL_MODE:
5959                    if (message.arg1 == CONNECT_MODE) {
5960
5961                        if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
5962                            setWifiState(WIFI_STATE_ENABLED);
5963                            // Load and re-enable networks when going back to enabled state
5964                            // This is essential for networks to show up after restore
5965                            mWifiConfigManager.loadAndEnableAllNetworks();
5966                            mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
5967                        } else {
5968                            mWifiConfigManager.enableAllNetworks();
5969                        }
5970                        // start a scan to trigger Quality network selection
5971                        startScan(ENABLE_WIFI, 0, null, null);
5972
5973                        // Loose last selection choice since user toggled WiFi
5974                        mWifiConfigManager.
5975                                setAndEnableLastSelectedConfiguration(
5976                                        WifiConfiguration.INVALID_NETWORK_ID);
5977
5978                        mOperationalMode = CONNECT_MODE;
5979                        transitionTo(mDisconnectedState);
5980                    } else {
5981                        // Nothing to do
5982                        return HANDLED;
5983                    }
5984                    break;
5985                // Handle scan. All the connection related commands are
5986                // handled only in ConnectModeState
5987                case CMD_START_SCAN:
5988                    handleScanRequest(message);
5989                    break;
5990                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5991                    SupplicantState state = handleSupplicantStateChange(message);
5992                    if (DBG) log("SupplicantState= " + state);
5993                    break;
5994                default:
5995                    return NOT_HANDLED;
5996            }
5997            return HANDLED;
5998        }
5999    }
6000
6001
6002    String smToString(Message message) {
6003        return smToString(message.what);
6004    }
6005
6006    String smToString(int what) {
6007        String s = sSmToString.get(what);
6008        if (s != null) {
6009            return s;
6010        }
6011        switch (what) {
6012            case WifiMonitor.DRIVER_HUNG_EVENT:
6013                s = "DRIVER_HUNG_EVENT";
6014                break;
6015            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
6016                s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
6017                break;
6018            case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
6019                s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
6020                break;
6021            case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6022                s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
6023                break;
6024            case WifiManager.DISABLE_NETWORK:
6025                s = "WifiManager.DISABLE_NETWORK";
6026                break;
6027            case WifiManager.CONNECT_NETWORK:
6028                s = "CONNECT_NETWORK";
6029                break;
6030            case WifiManager.SAVE_NETWORK:
6031                s = "SAVE_NETWORK";
6032                break;
6033            case WifiManager.FORGET_NETWORK:
6034                s = "FORGET_NETWORK";
6035                break;
6036            case WifiMonitor.SUP_CONNECTION_EVENT:
6037                s = "SUP_CONNECTION_EVENT";
6038                break;
6039            case WifiMonitor.SUP_DISCONNECTION_EVENT:
6040                s = "SUP_DISCONNECTION_EVENT";
6041                break;
6042            case WifiMonitor.SCAN_RESULTS_EVENT:
6043                s = "SCAN_RESULTS_EVENT";
6044                break;
6045            case WifiMonitor.SCAN_FAILED_EVENT:
6046                s = "SCAN_FAILED_EVENT";
6047                break;
6048            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6049                s = "SUPPLICANT_STATE_CHANGE_EVENT";
6050                break;
6051            case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6052                s = "AUTHENTICATION_FAILURE_EVENT";
6053                break;
6054            case WifiMonitor.SSID_TEMP_DISABLED:
6055                s = "SSID_TEMP_DISABLED";
6056                break;
6057            case WifiMonitor.SSID_REENABLED:
6058                s = "SSID_REENABLED";
6059                break;
6060            case WifiMonitor.WPS_SUCCESS_EVENT:
6061                s = "WPS_SUCCESS_EVENT";
6062                break;
6063            case WifiMonitor.WPS_FAIL_EVENT:
6064                s = "WPS_FAIL_EVENT";
6065                break;
6066            case WifiMonitor.SUP_REQUEST_IDENTITY:
6067                s = "SUP_REQUEST_IDENTITY";
6068                break;
6069            case WifiMonitor.NETWORK_CONNECTION_EVENT:
6070                s = "NETWORK_CONNECTION_EVENT";
6071                break;
6072            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6073                s = "NETWORK_DISCONNECTION_EVENT";
6074                break;
6075            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6076                s = "ASSOCIATION_REJECTION_EVENT";
6077                break;
6078            case WifiMonitor.ANQP_DONE_EVENT:
6079                s = "WifiMonitor.ANQP_DONE_EVENT";
6080                break;
6081            case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
6082                s = "WifiMonitor.RX_HS20_ANQP_ICON_EVENT";
6083                break;
6084            case WifiMonitor.GAS_QUERY_DONE_EVENT:
6085                s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
6086                break;
6087            case WifiMonitor.HS20_REMEDIATION_EVENT:
6088                s = "WifiMonitor.HS20_REMEDIATION_EVENT";
6089                break;
6090            case WifiMonitor.GAS_QUERY_START_EVENT:
6091                s = "WifiMonitor.GAS_QUERY_START_EVENT";
6092                break;
6093            case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
6094                s = "GROUP_CREATING_TIMED_OUT";
6095                break;
6096            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
6097                s = "P2P_CONNECTION_CHANGED";
6098                break;
6099            case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
6100                s = "P2P.DISCONNECT_WIFI_RESPONSE";
6101                break;
6102            case WifiP2pServiceImpl.SET_MIRACAST_MODE:
6103                s = "P2P.SET_MIRACAST_MODE";
6104                break;
6105            case WifiP2pServiceImpl.BLOCK_DISCOVERY:
6106                s = "P2P.BLOCK_DISCOVERY";
6107                break;
6108            case WifiP2pServiceImpl.SET_COUNTRY_CODE:
6109                s = "P2P.SET_COUNTRY_CODE";
6110                break;
6111            case WifiManager.CANCEL_WPS:
6112                s = "CANCEL_WPS";
6113                break;
6114            case WifiManager.CANCEL_WPS_FAILED:
6115                s = "CANCEL_WPS_FAILED";
6116                break;
6117            case WifiManager.CANCEL_WPS_SUCCEDED:
6118                s = "CANCEL_WPS_SUCCEDED";
6119                break;
6120            case WifiManager.START_WPS:
6121                s = "START_WPS";
6122                break;
6123            case WifiManager.START_WPS_SUCCEEDED:
6124                s = "START_WPS_SUCCEEDED";
6125                break;
6126            case WifiManager.WPS_FAILED:
6127                s = "WPS_FAILED";
6128                break;
6129            case WifiManager.WPS_COMPLETED:
6130                s = "WPS_COMPLETED";
6131                break;
6132            case WifiManager.RSSI_PKTCNT_FETCH:
6133                s = "RSSI_PKTCNT_FETCH";
6134                break;
6135            default:
6136                s = "what:" + Integer.toString(what);
6137                break;
6138        }
6139        return s;
6140    }
6141
6142    void registerConnected() {
6143        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6144            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6145            if (config != null) {
6146                //Here we will clear all disable counters once a network is connected
6147                //records how long this network is connected in future
6148                config.lastConnected = System.currentTimeMillis();
6149                config.getNetworkSelectionStatus().clearDisableReasonCounter();
6150                config.numAssociation++;
6151            }
6152            // On connect, reset wifiScoreReport
6153            mWifiScoreReport = null;
6154       }
6155    }
6156
6157    void registerDisconnected() {
6158        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6159            // We are switching away from this configuration,
6160            // hence record the time we were connected last
6161            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6162            if (config != null) {
6163                config.lastDisconnected = System.currentTimeMillis();
6164                if (config.ephemeral) {
6165                    // Remove ephemeral WifiConfigurations from file
6166                    mWifiConfigManager.forgetNetwork(mLastNetworkId);
6167                }
6168            }
6169        }
6170    }
6171
6172    void noteWifiDisabledWhileAssociated() {
6173        // We got disabled by user while we were associated, make note of it
6174        int rssi = mWifiInfo.getRssi();
6175        WifiConfiguration config = getCurrentWifiConfiguration();
6176        if (getCurrentState() == mConnectedState
6177                && rssi != WifiInfo.INVALID_RSSI
6178                && config != null) {
6179            boolean is24GHz = mWifiInfo.is24GHz();
6180            boolean isBadRSSI = (is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi24.get())
6181                    || (!is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi5.get());
6182            boolean isLowRSSI =
6183                    (is24GHz && rssi < mWifiConfigManager.thresholdQualifiedRssi24.get())
6184                            || (!is24GHz && mWifiInfo.getRssi() <
6185                                    mWifiConfigManager.thresholdQualifiedRssi5.get());
6186            boolean isHighRSSI = (is24GHz && rssi
6187                    >= mWifiConfigManager.thresholdSaturatedRssi24.get())
6188                    || (!is24GHz && mWifiInfo.getRssi()
6189                    >= mWifiConfigManager.thresholdSaturatedRssi5.get());
6190            if (isBadRSSI) {
6191                // Take note that we got disabled while RSSI was Bad
6192                config.numUserTriggeredWifiDisableLowRSSI++;
6193            } else if (isLowRSSI) {
6194                // Take note that we got disabled while RSSI was Low
6195                config.numUserTriggeredWifiDisableBadRSSI++;
6196            } else if (!isHighRSSI) {
6197                // Take note that we got disabled while RSSI was Not high
6198                config.numUserTriggeredWifiDisableNotHighRSSI++;
6199            }
6200        }
6201    }
6202
6203    WifiConfiguration getCurrentWifiConfiguration() {
6204        if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
6205            return null;
6206        }
6207        return mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6208    }
6209
6210    ScanResult getCurrentScanResult() {
6211        WifiConfiguration config = getCurrentWifiConfiguration();
6212        if (config == null) {
6213            return null;
6214        }
6215        String BSSID = mWifiInfo.getBSSID();
6216        if (BSSID == null) {
6217            BSSID = mTargetRoamBSSID;
6218        }
6219        ScanDetailCache scanDetailCache =
6220                mWifiConfigManager.getScanDetailCache(config);
6221
6222        if (scanDetailCache == null) {
6223            return null;
6224        }
6225
6226        return scanDetailCache.get(BSSID);
6227    }
6228
6229    String getCurrentBSSID() {
6230        if (linkDebouncing) {
6231            return null;
6232        }
6233        return mLastBssid;
6234    }
6235
6236    class ConnectModeState extends State {
6237
6238        @Override
6239        public boolean processMessage(Message message) {
6240            WifiConfiguration config;
6241            int netId;
6242            boolean ok;
6243            boolean didDisconnect;
6244            String bssid;
6245            String ssid;
6246            NetworkUpdateResult result;
6247            logStateAndMessage(message, this);
6248
6249            switch (message.what) {
6250                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6251                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
6252                    didBlackListBSSID = false;
6253                    bssid = (String) message.obj;
6254                    if (bssid == null || TextUtils.isEmpty(bssid)) {
6255                        // If BSSID is null, use the target roam BSSID
6256                        bssid = mTargetRoamBSSID;
6257                    }
6258                    if (bssid != null) {
6259                        // If we have a BSSID, tell configStore to black list it
6260                        didBlackListBSSID = mWifiQualifiedNetworkSelector
6261                                .enableBssidForQualityNetworkSelection(bssid, false);
6262                    }
6263
6264                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
6265                            WifiConfiguration.NetworkSelectionStatus
6266                            .DISABLED_ASSOCIATION_REJECTION);
6267
6268                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
6269                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
6270                    mWifiMetrics.endConnectionEvent(
6271                            WifiMetrics.ConnectionEvent.LLF_ASSOCIATION_REJECTION,
6272                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6273                    break;
6274                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6275                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
6276                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
6277                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6278                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
6279                                WifiConfiguration.NetworkSelectionStatus
6280                                        .DISABLED_AUTHENTICATION_FAILURE);
6281                    }
6282                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
6283                    mWifiMetrics.endConnectionEvent(
6284                            WifiMetrics.ConnectionEvent.LLF_AUTHENTICATION_FAILURE,
6285                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6286                    break;
6287                case WifiMonitor.SSID_TEMP_DISABLED:
6288                    Log.e(TAG, "Supplicant SSID temporary disabled:"
6289                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
6290                    mWifiConfigManager.updateNetworkSelectionStatus(
6291                            message.arg1,
6292                            WifiConfiguration.NetworkSelectionStatus
6293                            .DISABLED_AUTHENTICATION_FAILURE);
6294                    mWifiMetrics.endConnectionEvent(
6295                            WifiMetrics.ConnectionEvent.LLF_SSID_TEMP_DISABLED,
6296                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6297                    break;
6298                case WifiMonitor.SSID_REENABLED:
6299                    Log.d(TAG, "Supplicant SSID reenable:"
6300                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
6301                    // Do not re-enable it in Quality Network Selection since framework has its own
6302                    // Algorithm of disable/enable
6303                    break;
6304                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6305                    SupplicantState state = handleSupplicantStateChange(message);
6306                    // A driver/firmware hang can now put the interface in a down state.
6307                    // We detect the interface going down and recover from it
6308                    if (!SupplicantState.isDriverActive(state)) {
6309                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
6310                            handleNetworkDisconnect();
6311                        }
6312                        log("Detected an interface down, restart driver");
6313                        transitionTo(mDriverStoppedState);
6314                        sendMessage(CMD_START_DRIVER);
6315                        break;
6316                    }
6317
6318                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
6319                    // when authentication times out after a successful connection,
6320                    // we can figure this from the supplicant state. If supplicant
6321                    // state is DISCONNECTED, but the mNetworkInfo says we are not
6322                    // disconnected, we need to handle a disconnection
6323                    if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
6324                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
6325                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
6326                        handleNetworkDisconnect();
6327                        transitionTo(mDisconnectedState);
6328                    }
6329
6330                    // If we have COMPLETED a connection to a BSSID, start doing
6331                    // DNAv4/DNAv6 -style probing for on-link neighbors of
6332                    // interest (e.g. routers); harmless if none are configured.
6333                    if (state == SupplicantState.COMPLETED) {
6334                        mIpManager.confirmConfiguration();
6335                    }
6336                    break;
6337                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6338                    if (message.arg1 == 1) {
6339                        mWifiNative.disconnect();
6340                        mTemporarilyDisconnectWifi = true;
6341                    } else {
6342                        mWifiNative.reconnect();
6343                        mTemporarilyDisconnectWifi = false;
6344                    }
6345                    break;
6346                case CMD_ADD_OR_UPDATE_NETWORK:
6347                    // Only the current foreground user can modify networks.
6348                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6349                        loge("Only the current foreground user can modify networks "
6350                                + " currentUserId=" + mCurrentUserId
6351                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6352                        replyToMessage(message, message.what, FAILURE);
6353                        break;
6354                    }
6355
6356                    config = (WifiConfiguration) message.obj;
6357
6358                    if (!recordUidIfAuthorized(config, message.sendingUid,
6359                            /* onlyAnnotate */ false)) {
6360                        logw("Not authorized to update network "
6361                             + " config=" + config.SSID
6362                             + " cnid=" + config.networkId
6363                             + " uid=" + message.sendingUid);
6364                        replyToMessage(message, message.what, FAILURE);
6365                        break;
6366                    }
6367
6368                    int res = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
6369                    if (res < 0) {
6370                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6371                    } else {
6372                        WifiConfiguration curConfig = getCurrentWifiConfiguration();
6373                        if (curConfig != null && config != null) {
6374                            WifiConfiguration.NetworkSelectionStatus networkStatus =
6375                                    config.getNetworkSelectionStatus();
6376                            if (curConfig.priority < config.priority && networkStatus != null
6377                                    && !networkStatus.isNetworkPermanentlyDisabled()) {
6378                                // Interpret this as a connect attempt
6379                                // Set the last selected configuration so as to allow the system to
6380                                // stick the last user choice without persisting the choice
6381                                mWifiConfigManager.setAndEnableLastSelectedConfiguration(res);
6382                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
6383                                boolean persist = mWifiConfigManager
6384                                        .checkConfigOverridePermission(message.sendingUid);
6385                                mWifiQualifiedNetworkSelector
6386                                        .userSelectNetwork(res, persist);
6387
6388                                // Remember time of last connection attempt
6389                                lastConnectAttemptTimestamp = System.currentTimeMillis();
6390                                mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6391
6392                                // As a courtesy to the caller, trigger a scan now
6393                                startScan(ADD_OR_UPDATE_SOURCE, 0, null, null);
6394                            }
6395                        }
6396                    }
6397                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
6398                    break;
6399                case CMD_REMOVE_NETWORK:
6400                    // Only the current foreground user can modify networks.
6401                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6402                        loge("Only the current foreground user can modify networks "
6403                                + " currentUserId=" + mCurrentUserId
6404                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6405                        replyToMessage(message, message.what, FAILURE);
6406                        break;
6407                    }
6408                    netId = message.arg1;
6409
6410                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
6411                            /* onlyAnnotate */ false)) {
6412                        logw("Not authorized to remove network "
6413                             + " cnid=" + netId
6414                             + " uid=" + message.sendingUid);
6415                        replyToMessage(message, message.what, FAILURE);
6416                        break;
6417                    }
6418
6419                    ok = mWifiConfigManager.removeNetwork(message.arg1);
6420                    if (!ok) {
6421                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6422                    }
6423                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
6424                    break;
6425                case CMD_ENABLE_NETWORK:
6426                    // Only the current foreground user can modify networks.
6427                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6428                        loge("Only the current foreground user can modify networks "
6429                                + " currentUserId=" + mCurrentUserId
6430                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6431                        replyToMessage(message, message.what, FAILURE);
6432                        break;
6433                    }
6434
6435                    boolean disableOthers = message.arg2 == 1;
6436                    netId = message.arg1;
6437                    config = mWifiConfigManager.getWifiConfiguration(netId);
6438                    if (config == null) {
6439                        loge("No network with id = " + netId);
6440                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6441                        replyToMessage(message, message.what, FAILURE);
6442                        break;
6443                    }
6444
6445                    // disable other only means select this network, does not mean all other
6446                    // networks need to be disabled
6447                    if (disableOthers) {
6448                        mWifiQualifiedNetworkSelector.enableNetworkByUser(config);
6449                        // Remember time of last connection attempt
6450                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6451                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6452                    }
6453                    // Cancel auto roam requests
6454                    autoRoamSetBSSID(netId, "any");
6455
6456                    int uid = message.sendingUid;
6457                    mWifiQualifiedNetworkSelector.enableNetworkByUser(config);
6458                    ok = mWifiConfigManager.enableNetwork(netId, disableOthers, uid);
6459                    if (!ok) {
6460                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6461                    } else if (disableOthers) {
6462                        mTargetNetworkId = netId;
6463                    }
6464
6465                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
6466                    break;
6467                case CMD_ENABLE_ALL_NETWORKS:
6468                    long time = android.os.SystemClock.elapsedRealtime();
6469                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
6470                        mWifiConfigManager.enableAllNetworks();
6471                        mLastEnableAllNetworksTime = time;
6472                    }
6473                    break;
6474                case WifiManager.DISABLE_NETWORK:
6475                    if (mWifiConfigManager.updateNetworkSelectionStatus(message.arg1,
6476                            WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) {
6477                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
6478                    } else {
6479                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6480                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
6481                                WifiManager.ERROR);
6482                    }
6483                    break;
6484                case CMD_DISABLE_EPHEMERAL_NETWORK:
6485                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
6486                    if (config != null) {
6487                        if (config.networkId == mLastNetworkId) {
6488                            // Disconnect and let autojoin reselect a new network
6489                            sendMessage(CMD_DISCONNECT);
6490                        }
6491                    }
6492                    break;
6493                case CMD_BLACKLIST_NETWORK:
6494                    mWifiConfigManager.blackListBssid((String) message.obj);
6495                    break;
6496                case CMD_CLEAR_BLACKLIST:
6497                    mWifiConfigManager.clearBssidBlacklist();
6498                    break;
6499                case CMD_SAVE_CONFIG:
6500                    ok = mWifiConfigManager.saveConfig();
6501
6502                    if (DBG) logd("did save config " + ok);
6503                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
6504
6505                    // Inform the backup manager about a data change
6506                    mBackupManagerProxy.notifyDataChanged();
6507                    break;
6508                case CMD_GET_CONFIGURED_NETWORKS:
6509                    replyToMessage(message, message.what,
6510                            mWifiConfigManager.getConfiguredNetworks());
6511                    break;
6512                case WifiMonitor.SUP_REQUEST_IDENTITY:
6513                    int networkId = message.arg2;
6514                    boolean identitySent = false;
6515                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
6516
6517                    if (targetWificonfiguration != null
6518                            && targetWificonfiguration.enterpriseConfig != null) {
6519                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
6520                    }
6521
6522                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
6523                    if (targetWificonfiguration != null
6524                            && targetWificonfiguration.networkId == networkId
6525                            && targetWificonfiguration.allowedKeyManagement
6526                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X)
6527                            &&  (eapMethod == WifiEnterpriseConfig.Eap.SIM
6528                            || eapMethod == WifiEnterpriseConfig.Eap.AKA
6529                            || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
6530                        TelephonyManager tm = (TelephonyManager)
6531                                mContext.getSystemService(Context.TELEPHONY_SERVICE);
6532                        if (tm != null) {
6533                            String imsi = tm.getSubscriberId();
6534                            String mccMnc = "";
6535
6536                            if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
6537                                 mccMnc = tm.getSimOperator();
6538
6539                            String identity = buildIdentity(eapMethod, imsi, mccMnc);
6540
6541                            if (!identity.isEmpty()) {
6542                                mWifiNative.simIdentityResponse(networkId, identity);
6543                                identitySent = true;
6544                            }
6545                        }
6546                    }
6547                    if (!identitySent) {
6548                        // Supplicant lacks credentials to connect to that network, hence black list
6549                        ssid = (String) message.obj;
6550                        if (targetWificonfiguration != null && ssid != null
6551                                && targetWificonfiguration.SSID != null
6552                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
6553                            mWifiConfigManager.updateNetworkSelectionStatus(targetWificonfiguration,
6554                                    WifiConfiguration.NetworkSelectionStatus
6555                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
6556                        }
6557                        // Disconnect now, as we don't have any way to fullfill
6558                        // the  supplicant request.
6559                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
6560                                WifiConfiguration.INVALID_NETWORK_ID);
6561                        mWifiNative.disconnect();
6562                    }
6563                    break;
6564                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
6565                    logd("Received SUP_REQUEST_SIM_AUTH");
6566                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
6567                    if (requestData != null) {
6568                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
6569                            handleGsmAuthRequest(requestData);
6570                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
6571                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
6572                            handle3GAuthRequest(requestData);
6573                        }
6574                    } else {
6575                        loge("Invalid sim auth request");
6576                    }
6577                    break;
6578                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
6579                    replyToMessage(message, message.what,
6580                            mWifiConfigManager.getPrivilegedConfiguredNetworks());
6581                    break;
6582                case CMD_GET_MATCHING_CONFIG:
6583                    replyToMessage(message, message.what,
6584                            mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
6585                    break;
6586                /* Do a redundant disconnect without transition */
6587                case CMD_DISCONNECT:
6588                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
6589                            (WifiConfiguration.INVALID_NETWORK_ID);
6590                    mWifiNative.disconnect();
6591                    break;
6592                case CMD_RECONNECT:
6593                    WifiConfiguration candidate =
6594                            mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
6595                            mAllowUntrustedConnections, mScanResults, linkDebouncing,
6596                            isConnected(), isDisconnected(), isSupplicantTransientState());
6597                    tryToConnectToNetwork(candidate);
6598                    break;
6599                case CMD_REASSOCIATE:
6600                    lastConnectAttemptTimestamp = System.currentTimeMillis();
6601                    mWifiNative.reassociate();
6602                    break;
6603                case CMD_RELOAD_TLS_AND_RECONNECT:
6604                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
6605                        logd("Reconnecting to give a chance to un-connected TLS networks");
6606                        mWifiNative.disconnect();
6607                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6608                        mWifiNative.reconnect();
6609                    }
6610                    break;
6611                case CMD_AUTO_ROAM:
6612                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6613                    return HANDLED;
6614                case CMD_AUTO_CONNECT:
6615                    /* Work Around: wpa_supplicant can get in a bad state where it returns a non
6616                     * associated status to the STATUS command but somehow-someplace still thinks
6617                     * it is associated and thus will ignore select/reconnect command with
6618                     * following message:
6619                     * "Already associated with the selected network - do nothing"
6620                     *
6621                     * Hence, sends a disconnect to supplicant first.
6622                     */
6623                    didDisconnect = false;
6624                    if (getCurrentState() != mDisconnectedState) {
6625                        /** Supplicant will ignore the reconnect if we are currently associated,
6626                         * hence trigger a disconnect
6627                         */
6628                        didDisconnect = true;
6629                        mWifiNative.disconnect();
6630                    }
6631
6632                    /* connect command coming from auto-join */
6633                    netId = message.arg1;
6634                    mTargetNetworkId = netId;
6635                    mTargetRoamBSSID = (String) message.obj;
6636                    config = mWifiConfigManager.getWifiConfiguration(netId);
6637                    logd("CMD_AUTO_CONNECT sup state "
6638                            + mSupplicantStateTracker.getSupplicantStateName()
6639                            + " my state " + getCurrentState().getName()
6640                            + " nid=" + Integer.toString(netId)
6641                            + " roam=" + Boolean.toString(mAutoRoaming));
6642                    if (config == null) {
6643                        loge("AUTO_CONNECT and no config, bail out...");
6644                        break;
6645                    }
6646
6647                    /* Make sure we cancel any previous roam request */
6648                    setTargetBssid(config, mTargetRoamBSSID);
6649
6650                    /* Save the network config */
6651                    logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
6652                            + " nid=" + Integer.toString(netId));
6653                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
6654                    netId = result.getNetworkId();
6655                    logd("CMD_AUTO_CONNECT did save config -> "
6656                            + " nid=" + Integer.toString(netId));
6657
6658                    // Since we updated the config,read it back from config store:
6659                    config = mWifiConfigManager.getWifiConfiguration(netId);
6660                    if (config == null) {
6661                        loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
6662                        break;
6663                    }
6664                    if (netId != config.networkId) {
6665                        loge("CMD_AUTO_CONNECT couldn't update the config, want"
6666                                + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
6667                        break;
6668                    }
6669
6670                    if (deferForUserInput(message, netId, false)) {
6671                        break;
6672                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
6673                                                                   WifiConfiguration.USER_BANNED) {
6674                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6675                                WifiManager.NOT_AUTHORIZED);
6676                        break;
6677                    }
6678
6679                    // If we're autojoining a network that the user or an app explicitly selected,
6680                    // keep track of the UID that selected it.
6681                    // TODO(b/26786318): Keep track of the lastSelectedConfiguration and the
6682                    // lastConnectUid on a per-user basis.
6683                    int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
6684
6685                    //Start a new ConnectionEvent due to auto_connect, assume we are connecting
6686                    //between different networks due to QNS, setting ROAM_UNRELATED
6687                    mWifiMetrics.startConnectionEvent(config,
6688                            WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
6689                    if (!didDisconnect) {
6690                        //If we were originally disconnected, then this was not any kind of ROAM
6691                        mWifiMetrics.setConnectionEventRoamType(
6692                                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
6693                    }
6694                    //Determine if this CONNECTION is for a user selection
6695                    if (mWifiConfigManager.isLastSelectedConfiguration(config)
6696                            && isCurrentUserProfile(UserHandle.getUserId(config.lastConnectUid))) {
6697                        lastConnectUid = config.lastConnectUid;
6698                        mWifiMetrics.setConnectionEventRoamType(
6699                                WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
6700                    }
6701                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
6702                            lastConnectUid) && mWifiNative.reconnect()) {
6703                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6704                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
6705                        config = mWifiConfigManager.getWifiConfiguration(netId);
6706                        if (config != null
6707                                && !mWifiConfigManager.isLastSelectedConfiguration(config)) {
6708                            // If we autojoined a different config than the user selected one,
6709                            // it means we could not see the last user selection,
6710                            // or that the last user selection was faulty and ended up blacklisted
6711                            // for some reason (in which case the user is notified with an error
6712                            // message in the Wifi picker), and thus we managed to auto-join away
6713                            // from the selected  config. -> in that case we need to forget
6714                            // the selection because we don't want to abruptly switch back to it.
6715                            //
6716                            // Note that the user selection is also forgotten after a period of time
6717                            // during which the device has been disconnected.
6718                            // The default value is 30 minutes : see the code path at bottom of
6719                            // setScanResults() function.
6720                            mWifiConfigManager.
6721                                 setAndEnableLastSelectedConfiguration(
6722                                         WifiConfiguration.INVALID_NETWORK_ID);
6723                        }
6724                        mAutoRoaming = false;
6725                        if (isRoaming() || linkDebouncing) {
6726                            transitionTo(mRoamingState);
6727                        } else if (didDisconnect) {
6728                            transitionTo(mDisconnectingState);
6729                        } else {
6730                            /* Already in disconnected state, nothing to change */
6731                            if (!mScreenOn && mLegacyPnoEnabled && mBackgroundScanSupported) {
6732                                int delay = 60 * 1000;
6733                                if (DBG) {
6734                                    logd("Starting PNO alarm: " + delay);
6735                                }
6736                                mAlarmManager.set(AlarmManager.RTC_WAKEUP,
6737                                       System.currentTimeMillis() + delay,
6738                                       mPnoIntent);
6739                            }
6740                            mRestartAutoJoinOffloadCounter++;
6741                        }
6742                    } else {
6743                        loge("Failed to connect config: " + config + " netId: " + netId);
6744                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6745                                WifiManager.ERROR);
6746                        mWifiMetrics.endConnectionEvent(
6747                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
6748                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6749                        break;
6750                    }
6751                    break;
6752                case CMD_REMOVE_APP_CONFIGURATIONS:
6753                    mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
6754                    break;
6755                case CMD_REMOVE_USER_CONFIGURATIONS:
6756                    mWifiConfigManager.removeNetworksForUser(message.arg1);
6757                    break;
6758                case WifiManager.CONNECT_NETWORK:
6759                    // Only the current foreground user can modify networks.
6760                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6761                        loge("Only the current foreground user can modify networks "
6762                                + " currentUserId=" + mCurrentUserId
6763                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6764                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6765                                       WifiManager.NOT_AUTHORIZED);
6766                        break;
6767                    }
6768
6769                    /**
6770                     *  The connect message can contain a network id passed as arg1 on message or
6771                     * or a config passed as obj on message.
6772                     * For a new network, a config is passed to create and connect.
6773                     * For an existing network, a network id is passed
6774                     */
6775                    netId = message.arg1;
6776                    config = (WifiConfiguration) message.obj;
6777                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6778                    boolean updatedExisting = false;
6779
6780                    /* Save the network config */
6781                    if (config != null) {
6782                        // When connecting to an access point, WifiStateMachine wants to update the
6783                        // relevant config with administrative data. This update should not be
6784                        // considered a 'real' update, therefore lockdown by Device Owner must be
6785                        // disregarded.
6786                        if (!recordUidIfAuthorized(config, message.sendingUid,
6787                                /* onlyAnnotate */ true)) {
6788                            logw("Not authorized to update network "
6789                                 + " config=" + config.SSID
6790                                 + " cnid=" + config.networkId
6791                                 + " uid=" + message.sendingUid);
6792                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6793                                           WifiManager.NOT_AUTHORIZED);
6794                            break;
6795                        }
6796                        String configKey = config.configKey(true /* allowCached */);
6797                        WifiConfiguration savedConfig =
6798                                mWifiConfigManager.getWifiConfiguration(configKey);
6799                        if (savedConfig != null) {
6800                            // There is an existing config with this netId, but it wasn't exposed
6801                            // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigManager#
6802                            // getConfiguredNetworks). Remove those bits and update the config.
6803                            config = savedConfig;
6804                            logd("CONNECT_NETWORK updating existing config with id=" +
6805                                    config.networkId + " configKey=" + configKey);
6806                            config.ephemeral = false;
6807                            mWifiConfigManager.updateNetworkSelectionStatus(config,
6808                                    WifiConfiguration.NetworkSelectionStatus
6809                                    .NETWORK_SELECTION_ENABLE);
6810                            updatedExisting = true;
6811                        }
6812
6813                        result = mWifiConfigManager.saveNetwork(config, message.sendingUid);
6814                        netId = result.getNetworkId();
6815                    }
6816                    config = mWifiConfigManager.getWifiConfiguration(netId);
6817                    if (config == null) {
6818                        logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
6819                                + mSupplicantStateTracker.getSupplicantStateName() + " my state "
6820                                + getCurrentState().getName());
6821                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6822                                WifiManager.ERROR);
6823                        break;
6824                    }
6825                    mTargetNetworkId = netId;
6826                    autoRoamSetBSSID(netId, "any");
6827                    if (message.sendingUid == Process.WIFI_UID
6828                        || message.sendingUid == Process.SYSTEM_UID) {
6829                        // As a sanity measure, clear the BSSID in the supplicant network block.
6830                        // If system or Wifi Settings want to connect, they will not
6831                        // specify the BSSID.
6832                        // If an app however had added a BSSID to this configuration, and the BSSID
6833                        // was wrong, Then we would forever fail to connect until that BSSID
6834                        // is cleaned up.
6835                        clearConfigBSSID(config, "CONNECT_NETWORK");
6836                    }
6837
6838                    if (deferForUserInput(message, netId, true)) {
6839                        break;
6840                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
6841                                                                    WifiConfiguration.USER_BANNED) {
6842                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6843                                WifiManager.NOT_AUTHORIZED);
6844                        break;
6845                    }
6846
6847                    mAutoRoaming = false;
6848
6849                    /* Tell network selection the user did try to connect to that network if from
6850                    settings */
6851                    boolean persist =
6852                        mWifiConfigManager.checkConfigOverridePermission(message.sendingUid);
6853
6854
6855                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(netId);
6856                    mWifiQualifiedNetworkSelector.userSelectNetwork(netId, persist);
6857                    didDisconnect = false;
6858                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
6859                            && mLastNetworkId != netId) {
6860                        /** Supplicant will ignore the reconnect if we are currently associated,
6861                         * hence trigger a disconnect
6862                         */
6863                        didDisconnect = true;
6864                        mWifiNative.disconnect();
6865                    }
6866
6867                    //Start a new ConnectionEvent due to connect_network, this is always user
6868                    //selected
6869                    mWifiMetrics.startConnectionEvent(config,
6870                            WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
6871                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ true,
6872                            message.sendingUid) && mWifiNative.reconnect()) {
6873                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6874                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
6875
6876                        /* The state tracker handles enabling networks upon completion/failure */
6877                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
6878                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
6879                        if (didDisconnect) {
6880                            /* Expect a disconnection from the old connection */
6881                            transitionTo(mDisconnectingState);
6882                        } else if (updatedExisting && getCurrentState() == mConnectedState &&
6883                                getCurrentWifiConfiguration().networkId == netId) {
6884                            // Update the current set of network capabilities, but stay in the
6885                            // current state.
6886                            updateCapabilities(config);
6887                        } else {
6888                            /**
6889                             * Directly go to disconnected state where we
6890                             * process the connection events from supplicant
6891                             */
6892                            transitionTo(mDisconnectedState);
6893                        }
6894                    } else {
6895                        loge("Failed to connect config: " + config + " netId: " + netId);
6896                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6897                                WifiManager.ERROR);
6898                        mWifiMetrics.endConnectionEvent(
6899                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
6900                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6901                        break;
6902                    }
6903                    break;
6904                case WifiManager.SAVE_NETWORK:
6905                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6906                    // Fall thru
6907                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
6908                    // Only the current foreground user can modify networks.
6909                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6910                        loge("Only the current foreground user can modify networks "
6911                                + " currentUserId=" + mCurrentUserId
6912                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6913                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6914                                WifiManager.NOT_AUTHORIZED);
6915                        break;
6916                    }
6917
6918                    lastSavedConfigurationAttempt = null; // Used for debug
6919                    config = (WifiConfiguration) message.obj;
6920                    if (config == null) {
6921                        loge("ERROR: SAVE_NETWORK with null configuration"
6922                                + mSupplicantStateTracker.getSupplicantStateName()
6923                                + " my state " + getCurrentState().getName());
6924                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6925                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6926                                WifiManager.ERROR);
6927                        break;
6928                    }
6929                    lastSavedConfigurationAttempt = new WifiConfiguration(config);
6930                    int nid = config.networkId;
6931                    logd("SAVE_NETWORK id=" + Integer.toString(nid)
6932                                + " config=" + config.SSID
6933                                + " nid=" + config.networkId
6934                                + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
6935                                + " my state " + getCurrentState().getName());
6936
6937                    // Only record the uid if this is user initiated
6938                    boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
6939                    if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
6940                            /* onlyAnnotate */ false)) {
6941                        logw("Not authorized to update network "
6942                             + " config=" + config.SSID
6943                             + " cnid=" + config.networkId
6944                             + " uid=" + message.sendingUid);
6945                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
6946                                       WifiManager.NOT_AUTHORIZED);
6947                        break;
6948                    }
6949
6950                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
6951                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
6952                        if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
6953                            if (result.hasIpChanged()) {
6954                                // The currently connection configuration was changed
6955                                // We switched from DHCP to static or from static to DHCP, or the
6956                                // static IP address has changed.
6957                                log("Reconfiguring IP on connection");
6958                                // TODO: clear addresses and disable IPv6
6959                                // to simplify obtainingIpState.
6960                                transitionTo(mObtainingIpState);
6961                            }
6962                            if (result.hasProxyChanged()) {
6963                                log("Reconfiguring proxy on connection");
6964                                mIpManager.setHttpProxy(
6965                                        mWifiConfigManager.getProxyProperties(mLastNetworkId));
6966                            }
6967                        }
6968                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
6969                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
6970
6971                        if (DBG) {
6972                           logd("Success save network nid="
6973                                    + Integer.toString(result.getNetworkId()));
6974                        }
6975
6976                        /**
6977                         * If the command comes from WifiManager, then
6978                         * tell autojoin the user did try to modify and save that network,
6979                         * and interpret the SAVE_NETWORK as a request to connect
6980                         */
6981                        boolean user = message.what == WifiManager.SAVE_NETWORK;
6982
6983                        // Did this connect come from settings
6984                        boolean persistConnect =
6985                                mWifiConfigManager.checkConfigOverridePermission(
6986                                        message.sendingUid);
6987
6988                        if (user) {
6989                            mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
6990                            mWifiConfigManager.writeKnownNetworkHistory();
6991                        }
6992                        //Fixme, CMD_AUTO_SAVE_NETWORK can be cleaned
6993                        mWifiQualifiedNetworkSelector.userSelectNetwork(
6994                                result.getNetworkId(), persistConnect);
6995                        candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
6996                                mAllowUntrustedConnections, mScanResults, linkDebouncing,
6997                                isConnected(), isDisconnected(), isSupplicantTransientState());
6998                        tryToConnectToNetwork(candidate);
6999                    } else {
7000                        loge("Failed to save network");
7001                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7002                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7003                                WifiManager.ERROR);
7004                    }
7005                    break;
7006                case WifiManager.FORGET_NETWORK:
7007                    // Only the current foreground user can modify networks.
7008                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
7009                        loge("Only the current foreground user can modify networks "
7010                                + " currentUserId=" + mCurrentUserId
7011                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
7012                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7013                                WifiManager.NOT_AUTHORIZED);
7014                        break;
7015                    }
7016
7017                    // Debug only, remember last configuration that was forgotten
7018                    WifiConfiguration toRemove
7019                            = mWifiConfigManager.getWifiConfiguration(message.arg1);
7020                    if (toRemove == null) {
7021                        lastForgetConfigurationAttempt = null;
7022                    } else {
7023                        lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
7024                    }
7025                    // check that the caller owns this network
7026                    netId = message.arg1;
7027
7028                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
7029                            /* onlyAnnotate */ false)) {
7030                        logw("Not authorized to forget network "
7031                             + " cnid=" + netId
7032                             + " uid=" + message.sendingUid);
7033                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7034                                WifiManager.NOT_AUTHORIZED);
7035                        break;
7036                    }
7037
7038                    if (mWifiConfigManager.forgetNetwork(message.arg1)) {
7039                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
7040                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
7041                                (WifiConfiguration) message.obj);
7042                    } else {
7043                        loge("Failed to forget network");
7044                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7045                                WifiManager.ERROR);
7046                    }
7047                    break;
7048                case WifiManager.START_WPS:
7049                    WpsInfo wpsInfo = (WpsInfo) message.obj;
7050                    WpsResult wpsResult;
7051                    switch (wpsInfo.setup) {
7052                        case WpsInfo.PBC:
7053                            wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
7054                            break;
7055                        case WpsInfo.KEYPAD:
7056                            wpsResult = mWifiConfigManager.startWpsWithPinFromAccessPoint(wpsInfo);
7057                            break;
7058                        case WpsInfo.DISPLAY:
7059                            wpsResult = mWifiConfigManager.startWpsWithPinFromDevice(wpsInfo);
7060                            break;
7061                        default:
7062                            wpsResult = new WpsResult(Status.FAILURE);
7063                            loge("Invalid setup for WPS");
7064                            break;
7065                    }
7066                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
7067                            (WifiConfiguration.INVALID_NETWORK_ID);
7068                    if (wpsResult.status == Status.SUCCESS) {
7069                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
7070                        transitionTo(mWpsRunningState);
7071                    } else {
7072                        loge("Failed to start WPS with config " + wpsInfo.toString());
7073                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
7074                    }
7075                    break;
7076                case CMD_ASSOCIATED_BSSID:
7077                    // This is where we can confirm the connection BSSID. Use it to find the
7078                    // right ScanDetail to populate metrics.
7079                    String someBssid = (String) message.obj;
7080                    if (someBssid != null) {
7081                        //Get the config associated with this connection attempt
7082                        WifiConfiguration someConf =
7083                                mWifiConfigManager.getWifiConfiguration(mTargetNetworkId);
7084                        // Get the ScanDetail associated with this BSSID
7085                        ScanDetailCache scanDetailCache = mWifiConfigManager.getScanDetailCache(
7086                                someConf);
7087                        if (scanDetailCache != null) {
7088                            mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
7089                                    someBssid));
7090                        }
7091                    }
7092                    return NOT_HANDLED;
7093                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7094                    if (DBG) log("Network connection established");
7095                    mLastNetworkId = message.arg1;
7096                    mLastBssid = (String) message.obj;
7097
7098                    mWifiInfo.setBSSID(mLastBssid);
7099                    mWifiInfo.setNetworkId(mLastNetworkId);
7100                    mWifiQualifiedNetworkSelector
7101                            .enableBssidForQualityNetworkSelection(mLastBssid, true);
7102                    sendNetworkStateChangeBroadcast(mLastBssid);
7103                    transitionTo(mObtainingIpState);
7104                    break;
7105                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7106                    // Calling handleNetworkDisconnect here is redundant because we might already
7107                    // have called it when leaving L2ConnectedState to go to disconnecting state
7108                    // or thru other path
7109                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
7110                    // if they are valid, and only in this case call handleNEtworkDisconnect,
7111                    // TODO: this should be fixed for a L MR release
7112                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
7113                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
7114                    // at the chip etc...
7115                    if (DBG) log("ConnectModeState: Network connection lost ");
7116                    handleNetworkDisconnect();
7117                    transitionTo(mDisconnectedState);
7118                    break;
7119                case CMD_PNO_NETWORK_FOUND:
7120                    processPnoNetworkFound((ScanResult[]) message.obj);
7121                    break;
7122                case CMD_ADD_PASSPOINT_MO:
7123                    res = mWifiConfigManager.addPasspointManagementObject((String) message.obj);
7124                    replyToMessage(message, message.what, res);
7125                    break;
7126                case CMD_MODIFY_PASSPOINT_MO:
7127                    if (message.obj != null) {
7128                        Bundle bundle = (Bundle) message.obj;
7129                        ArrayList<PasspointManagementObjectDefinition> mos =
7130                                bundle.getParcelableArrayList("MOS");
7131                        res = mWifiConfigManager.modifyPasspointMo(bundle.getString("FQDN"), mos);
7132                    } else {
7133                        res = 0;
7134                    }
7135                    replyToMessage(message, message.what, res);
7136
7137                    break;
7138                case CMD_QUERY_OSU_ICON:
7139                    if (mWifiConfigManager.queryPasspointIcon(
7140                            ((Bundle) message.obj).getLong("BSSID"),
7141                            ((Bundle) message.obj).getString("FILENAME"))) {
7142                        res = 1;
7143                    } else {
7144                        res = 0;
7145                    }
7146                    replyToMessage(message, message.what, res);
7147                    break;
7148                case CMD_MATCH_PROVIDER_NETWORK:
7149                    res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
7150                    replyToMessage(message, message.what, res);
7151                    break;
7152                default:
7153                    return NOT_HANDLED;
7154            }
7155            return HANDLED;
7156        }
7157    }
7158
7159    private void updateCapabilities(WifiConfiguration config) {
7160        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
7161        if (config != null) {
7162            if (config.ephemeral) {
7163                networkCapabilities.removeCapability(
7164                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7165            } else {
7166                networkCapabilities.addCapability(
7167                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7168            }
7169            networkCapabilities.setSignalStrength(mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI ?
7170                    mWifiInfo.getRssi() : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
7171        }
7172        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
7173    }
7174
7175    private class WifiNetworkAgent extends NetworkAgent {
7176        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
7177                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
7178            super(l, c, TAG, ni, nc, lp, score, misc);
7179        }
7180        protected void unwanted() {
7181            // Ignore if we're not the current networkAgent.
7182            if (this != mNetworkAgent) return;
7183            if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
7184                    + Integer.toString(mWifiInfo.score));
7185            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
7186        }
7187
7188        @Override
7189        protected void networkStatus(int status) {
7190            if (this != mNetworkAgent) return;
7191            if (status == NetworkAgent.INVALID_NETWORK) {
7192                if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
7193                        + Integer.toString(mWifiInfo.score));
7194                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
7195            } else if (status == NetworkAgent.VALID_NETWORK) {
7196                if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
7197                        + Integer.toString(mWifiInfo.score));
7198                doNetworkStatus(status);
7199            }
7200        }
7201
7202        @Override
7203        protected void saveAcceptUnvalidated(boolean accept) {
7204            if (this != mNetworkAgent) return;
7205            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
7206        }
7207
7208        @Override
7209        protected void startPacketKeepalive(Message msg) {
7210            WifiStateMachine.this.sendMessage(
7211                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
7212        }
7213
7214        @Override
7215        protected void stopPacketKeepalive(Message msg) {
7216            WifiStateMachine.this.sendMessage(
7217                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
7218        }
7219
7220        @Override
7221        protected void setSignalStrengthThresholds(int[] thresholds) {
7222            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
7223            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
7224            //    MAX_VALUE at the start/end of the thresholds array if necessary.
7225            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
7226            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
7227            //    re-arm the hardware event. This needs to be done on the state machine thread to
7228            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
7229            //    sent in the NetworkCapabilities) must be the one received from the hardware event
7230            //    received, or we might skip callbacks.
7231            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
7232            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
7233            if (thresholds.length == 0) {
7234                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
7235                        mWifiInfo.getRssi());
7236                return;
7237            }
7238            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
7239            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
7240            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
7241            Arrays.sort(rssiVals);
7242            byte[] rssiRange = new byte[rssiVals.length];
7243            for (int i = 0; i < rssiVals.length; i++) {
7244                int val = rssiVals[i];
7245                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
7246                    rssiRange[i] = (byte) val;
7247                } else {
7248                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
7249                            + Arrays.toString(rssiVals));
7250                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
7251                            mWifiInfo.getRssi());
7252                    return;
7253                }
7254            }
7255            // TODO: Do we quash rssi values in this sorted array which are very close?
7256            mRssiRanges = rssiRange;
7257            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
7258                    mWifiInfo.getRssi());
7259        }
7260
7261        @Override
7262        protected void preventAutomaticReconnect() {
7263            if (this != mNetworkAgent) return;
7264            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
7265        }
7266
7267        @Override
7268        protected boolean installPacketFilter(byte[] filter) {
7269            return mWifiNative.installPacketFilter(filter);
7270        }
7271    }
7272
7273    void unwantedNetwork(int reason) {
7274        sendMessage(CMD_UNWANTED_NETWORK, reason);
7275    }
7276
7277    void doNetworkStatus(int status) {
7278        sendMessage(CMD_NETWORK_STATUS, status);
7279    }
7280
7281    // rfc4186 & rfc4187:
7282    // create Permanent Identity base on IMSI,
7283    // identity = usernam@realm
7284    // with username = prefix | IMSI
7285    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
7286    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
7287        String mcc;
7288        String mnc;
7289        String prefix;
7290
7291        if (imsi == null || imsi.isEmpty())
7292            return "";
7293
7294        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
7295            prefix = "1";
7296        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
7297            prefix = "0";
7298        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
7299            prefix = "6";
7300        else  // not a valide EapMethod
7301            return "";
7302
7303        /* extract mcc & mnc from mccMnc */
7304        if (mccMnc != null && !mccMnc.isEmpty()) {
7305            mcc = mccMnc.substring(0, 3);
7306            mnc = mccMnc.substring(3);
7307            if (mnc.length() == 2)
7308                mnc = "0" + mnc;
7309        } else {
7310            // extract mcc & mnc from IMSI, assume mnc size is 3
7311            mcc = imsi.substring(0, 3);
7312            mnc = imsi.substring(3, 6);
7313        }
7314
7315        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
7316    }
7317
7318    boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
7319        if (config == null)
7320            return false;
7321
7322        // We are still seeing a fairly high power consumption triggered by autojoin scans
7323        // Hence do partial scans only for PSK configuration that are roamable since the
7324        // primary purpose of the partial scans is roaming.
7325        // Full badn scans with exponential backoff for the purpose or extended roaming and
7326        // network switching are performed unconditionally.
7327        ScanDetailCache scanDetailCache =
7328                mWifiConfigManager.getScanDetailCache(config);
7329        if (scanDetailCache == null
7330                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
7331                || scanDetailCache.size() > 6) {
7332            //return true but to not trigger the scan
7333            return true;
7334        }
7335        HashSet<Integer> freqs = mWifiConfigManager.makeChannelList(config,
7336                ONE_HOUR_MILLI, restrictChannelList);
7337        if (freqs != null && freqs.size() != 0) {
7338            //if (DBG) {
7339            logd("starting scan for " + config.configKey() + " with " + freqs);
7340            //}
7341            Set<Integer> hiddenNetworkIds = new HashSet<>();
7342            if (config.hiddenSSID) {
7343                hiddenNetworkIds.add(config.networkId);
7344            }
7345            // Call wifi native to start the scan
7346            if (startScanNative(freqs, hiddenNetworkIds)) {
7347                // Only count battery consumption if scan request is accepted
7348                noteScanStart(SCAN_ALARM_SOURCE, null);
7349                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
7350            } else {
7351                // used for debug only, mark scan as failed
7352                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
7353            }
7354            return true;
7355        } else {
7356            if (DBG) logd("no channels for " + config.configKey());
7357            return false;
7358        }
7359    }
7360
7361    void clearCurrentConfigBSSID(String dbg) {
7362        // Clear the bssid in the current config's network block
7363        WifiConfiguration config = getCurrentWifiConfiguration();
7364        if (config == null)
7365            return;
7366        clearConfigBSSID(config, dbg);
7367    }
7368    void clearConfigBSSID(WifiConfiguration config, String dbg) {
7369        if (config == null)
7370            return;
7371        if (DBG) {
7372            logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
7373                    + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
7374                    + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
7375        }
7376        if (DBG) {
7377           logd(dbg + " " + config.SSID
7378                    + " nid=" + Integer.toString(config.networkId));
7379        }
7380        mWifiConfigManager.saveWifiConfigBSSID(config, "any");
7381    }
7382
7383    class L2ConnectedState extends State {
7384        @Override
7385        public void enter() {
7386            mRssiPollToken++;
7387            if (mEnableRssiPolling) {
7388                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
7389            }
7390            if (mNetworkAgent != null) {
7391                loge("Have NetworkAgent when entering L2Connected");
7392                setNetworkDetailedState(DetailedState.DISCONNECTED);
7393            }
7394            setNetworkDetailedState(DetailedState.CONNECTING);
7395
7396            WifiNative.PacketFilterCapabilities packetFilterCapabilities =
7397                    mWifiNative.getPacketFilterCapabilities();
7398            if (packetFilterCapabilities != null) {
7399                mNetworkMisc.apfVersionSupported =
7400                        packetFilterCapabilities.apfVersionSupported;
7401                mNetworkMisc.maximumApfProgramSize =
7402                        packetFilterCapabilities.maximumApfProgramSize;
7403                mNetworkMisc.apfPacketFormat = ARPHRD_ETHER;
7404            }
7405
7406            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
7407                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
7408                    mLinkProperties, 60, mNetworkMisc);
7409
7410            // We must clear the config BSSID, as the wifi chipset may decide to roam
7411            // from this point on and having the BSSID specified in the network block would
7412            // cause the roam to faile and the device to disconnect
7413            clearCurrentConfigBSSID("L2ConnectedState");
7414        }
7415
7416        @Override
7417        public void exit() {
7418            mIpManager.stop();
7419
7420            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
7421            // Bug: 15347363
7422            // For paranoia's sake, call handleNetworkDisconnect
7423            // only if BSSID is null or last networkId
7424            // is not invalid.
7425            if (DBG) {
7426                StringBuilder sb = new StringBuilder();
7427                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
7428                if (mLastBssid !=null) {
7429                    sb.append(" ").append(mLastBssid);
7430                }
7431            }
7432            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
7433                handleNetworkDisconnect();
7434            }
7435        }
7436
7437        @Override
7438        public boolean processMessage(Message message) {
7439            logStateAndMessage(message, this);
7440
7441            switch (message.what) {
7442                case DhcpClient.CMD_PRE_DHCP_ACTION:
7443                    handlePreDhcpSetup();
7444                    break;
7445                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
7446                    mIpManager.completedPreDhcpAction();
7447                    break;
7448                case DhcpClient.CMD_POST_DHCP_ACTION:
7449                    handlePostDhcpSetup();
7450                    // We advance to mConnectedState because IpManager will also send a
7451                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
7452                    // which calls updateLinkProperties, which then sends
7453                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
7454                    //
7455                    // In the event of failure, we transition to mDisconnectingState
7456                    // similarly--via messages sent back from IpManager.
7457                    break;
7458                case CMD_IPV4_PROVISIONING_SUCCESS: {
7459                    handleIPv4Success((DhcpResults) message.obj);
7460                    break;
7461                }
7462                case CMD_IPV4_PROVISIONING_FAILURE: {
7463                    handleIPv4Failure();
7464                    break;
7465                }
7466                case CMD_IP_CONFIGURATION_SUCCESSFUL:
7467                    handleSuccessfulIpConfiguration();
7468                    mWifiMetrics.endConnectionEvent(
7469                            WifiMetrics.ConnectionEvent.LLF_NONE,
7470                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
7471                    sendConnectedState();
7472                    transitionTo(mConnectedState);
7473                    break;
7474                case CMD_IP_CONFIGURATION_LOST:
7475                    // Get Link layer stats so that we get fresh tx packet counters.
7476                    getWifiLinkLayerStats(true);
7477                    handleIpConfigurationLost();
7478                    transitionTo(mDisconnectingState);
7479                    break;
7480                case CMD_IP_REACHABILITY_LOST:
7481                    if (DBG && message.obj != null) log((String) message.obj);
7482                    handleIpReachabilityLost();
7483                    transitionTo(mDisconnectingState);
7484                    break;
7485                case CMD_DISCONNECT:
7486                    mWifiNative.disconnect();
7487                    transitionTo(mDisconnectingState);
7488                    break;
7489                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
7490                    if (message.arg1 == 1) {
7491                        mWifiNative.disconnect();
7492                        mTemporarilyDisconnectWifi = true;
7493                        transitionTo(mDisconnectingState);
7494                    }
7495                    break;
7496                case CMD_SET_OPERATIONAL_MODE:
7497                    if (message.arg1 != CONNECT_MODE) {
7498                        sendMessage(CMD_DISCONNECT);
7499                        deferMessage(message);
7500                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
7501                            noteWifiDisabledWhileAssociated();
7502                        }
7503                    }
7504                    mWifiConfigManager.
7505                                setAndEnableLastSelectedConfiguration(
7506                                        WifiConfiguration.INVALID_NETWORK_ID);
7507                    break;
7508                case CMD_SET_COUNTRY_CODE:
7509                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
7510                    deferMessage(message);
7511                    break;
7512                case CMD_START_SCAN:
7513                    if (DBG) {
7514                        logd("CMD_START_SCAN source " + message.arg1
7515                              + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
7516                              + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
7517                              + " targetRoamBSSID=" + mTargetRoamBSSID
7518                              + " RSSI=" + mWifiInfo.getRssi());
7519                    }
7520                    if (message.arg1 == SCAN_ALARM_SOURCE) {
7521                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
7522                        // not be processed) and restart the scan if neede
7523                        if (!getEnableAutoJoinWhenAssociated()) {
7524                            return HANDLED;
7525                        }
7526                        boolean shouldScan = mScreenOn;
7527
7528                        if (!checkAndRestartDelayedScan(message.arg2,
7529                                shouldScan,
7530                                mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get(),
7531                                null, null)) {
7532                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
7533                            logd("L2Connected CMD_START_SCAN source "
7534                                    + message.arg1
7535                                    + " " + message.arg2 + ", " + mDelayedScanCounter
7536                                    + " -> obsolete");
7537                            return HANDLED;
7538                        }
7539                        if (mP2pConnected.get()) {
7540                            logd("L2Connected CMD_START_SCAN source "
7541                                    + message.arg1
7542                                    + " " + message.arg2 + ", " + mDelayedScanCounter
7543                                    + " ignore because P2P is connected");
7544                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7545                            return HANDLED;
7546                        }
7547                        boolean tryFullBandScan = false;
7548                        boolean restrictChannelList = false;
7549                        long now_ms = System.currentTimeMillis();
7550                        if (DBG) {
7551                            logd("CMD_START_SCAN with age="
7552                                    + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
7553                                    + " interval=" + fullBandConnectedTimeIntervalMilli
7554                                    + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
7555                        }
7556                        if (mWifiInfo != null) {
7557                            if (mWifiConfigManager.enableFullBandScanWhenAssociated.get() &&
7558                                    (now_ms - lastFullBandConnectedTimeMilli)
7559                                    > fullBandConnectedTimeIntervalMilli) {
7560                                if (DBG) {
7561                                    logd("CMD_START_SCAN try full band scan age="
7562                                         + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
7563                                         + " interval=" + fullBandConnectedTimeIntervalMilli
7564                                         + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
7565                                }
7566                                tryFullBandScan = true;
7567                            }
7568
7569                            if (mWifiInfo.txSuccessRate >
7570                                    mWifiConfigManager.maxTxPacketForFullScans
7571                                    || mWifiInfo.rxSuccessRate >
7572                                    mWifiConfigManager.maxRxPacketForFullScans) {
7573                                // Too much traffic at the interface, hence no full band scan
7574                                if (DBG) {
7575                                    logd("CMD_START_SCAN " +
7576                                            "prevent full band scan due to pkt rate");
7577                                }
7578                                tryFullBandScan = false;
7579                            }
7580
7581                            if (mWifiInfo.txSuccessRate >
7582                                    mWifiConfigManager.maxTxPacketForPartialScans
7583                                    || mWifiInfo.rxSuccessRate >
7584                                    mWifiConfigManager.maxRxPacketForPartialScans) {
7585                                // Don't scan if lots of packets are being sent
7586                                restrictChannelList = true;
7587                                if (mWifiConfigManager.alwaysEnableScansWhileAssociated.get() ==
7588                                        0) {
7589                                    if (DBG) {
7590                                     logd("CMD_START_SCAN source " + message.arg1
7591                                        + " ...and ignore scans"
7592                                        + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate)
7593                                        + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate));
7594                                    }
7595                                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
7596                                    return HANDLED;
7597                                }
7598                            }
7599                        }
7600
7601                        WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
7602                        if (DBG) {
7603                            logd("CMD_START_SCAN full=" +
7604                                    tryFullBandScan);
7605                        }
7606                        if (currentConfiguration != null) {
7607                            if (fullBandConnectedTimeIntervalMilli <
7608                                    mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get()) {
7609                                // Sanity
7610                                fullBandConnectedTimeIntervalMilli =
7611                                        mWifiConfigManager
7612                                                .wifiAssociatedShortScanIntervalMilli.get();
7613                            }
7614                            if (tryFullBandScan) {
7615                                lastFullBandConnectedTimeMilli = now_ms;
7616                                if (fullBandConnectedTimeIntervalMilli
7617                                        < mWifiConfigManager.associatedFullScanMaxIntervalMilli) {
7618                                    // Increase the interval
7619                                    fullBandConnectedTimeIntervalMilli =
7620                                            fullBandConnectedTimeIntervalMilli *
7621                                                    mWifiConfigManager
7622                                                            .associatedFullScanBackoff.get() / 8;
7623
7624                                    if (DBG) {
7625                                        logd("CMD_START_SCAN bump interval ="
7626                                        + fullBandConnectedTimeIntervalMilli);
7627                                    }
7628                                }
7629                                handleScanRequest(message);
7630                            } else {
7631                                if (!startScanForConfiguration(
7632                                        currentConfiguration, restrictChannelList)) {
7633                                    if (DBG) {
7634                                        logd("starting scan, " +
7635                                                " did not find channels -> full");
7636                                    }
7637                                    lastFullBandConnectedTimeMilli = now_ms;
7638                                    if (fullBandConnectedTimeIntervalMilli
7639                                            < mWifiConfigManager
7640                                            .associatedFullScanMaxIntervalMilli) {
7641                                        // Increase the interval
7642                                        fullBandConnectedTimeIntervalMilli =
7643                                                fullBandConnectedTimeIntervalMilli *
7644                                                        mWifiConfigManager
7645                                                                .associatedFullScanBackoff.get() / 8;
7646
7647                                        if (DBG) {
7648                                            logd("CMD_START_SCAN bump interval ="
7649                                                    + fullBandConnectedTimeIntervalMilli);
7650                                        }
7651                                    }
7652                                    handleScanRequest(message);
7653                                }
7654                            }
7655
7656                        } else {
7657                            logd("CMD_START_SCAN : connected mode and no configuration");
7658                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
7659                        }
7660                    } else {
7661                        // Not scan alarm source
7662                        return NOT_HANDLED;
7663                    }
7664                    break;
7665                    /* Ignore connection to same network */
7666                case WifiManager.CONNECT_NETWORK:
7667                    int netId = message.arg1;
7668                    if (mWifiInfo.getNetworkId() == netId) {
7669                        break;
7670                    }
7671                    return NOT_HANDLED;
7672                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7673                    mWifiInfo.setBSSID((String) message.obj);
7674                    mLastNetworkId = message.arg1;
7675                    mWifiInfo.setNetworkId(mLastNetworkId);
7676                    if(!mLastBssid.equals((String) message.obj)) {
7677                        mLastBssid = (String) message.obj;
7678                        sendNetworkStateChangeBroadcast(mLastBssid);
7679                    }
7680                    break;
7681                case CMD_RSSI_POLL:
7682                    if (message.arg1 == mRssiPollToken) {
7683                        if (mWifiConfigManager.enableChipWakeUpWhenAssociated.get()) {
7684                            if (DBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
7685                            WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
7686                            if (stats != null) {
7687                                // Sanity check the results provided by driver
7688                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
7689                                        && (stats.rssi_mgmt == 0
7690                                        || stats.beacon_rx == 0)) {
7691                                    stats = null;
7692                                }
7693                            }
7694                            // Get Info and continue polling
7695                            fetchRssiLinkSpeedAndFrequencyNative();
7696                            mWifiScoreReport =
7697                                    WifiScoreReport.calculateScore(mWifiInfo,
7698                                                                   getCurrentWifiConfiguration(),
7699                                                                   mWifiConfigManager,
7700                                                                   mNetworkAgent,
7701                                                                   mWifiScoreReport,
7702                                                                   mAggressiveHandover);
7703                        }
7704                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
7705                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
7706                        if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
7707                    } else {
7708                        // Polling has completed
7709                    }
7710                    break;
7711                case CMD_ENABLE_RSSI_POLL:
7712                    cleanWifiScore();
7713                    if (mWifiConfigManager.enableRssiPollWhenAssociated.get()) {
7714                        mEnableRssiPolling = (message.arg1 == 1);
7715                    } else {
7716                        mEnableRssiPolling = false;
7717                    }
7718                    mRssiPollToken++;
7719                    if (mEnableRssiPolling) {
7720                        // First poll
7721                        fetchRssiLinkSpeedAndFrequencyNative();
7722                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
7723                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
7724                    }
7725                    break;
7726                case WifiManager.RSSI_PKTCNT_FETCH:
7727                    RssiPacketCountInfo info = new RssiPacketCountInfo();
7728                    fetchRssiLinkSpeedAndFrequencyNative();
7729                    info.rssi = mWifiInfo.getRssi();
7730                    fetchPktcntNative(info);
7731                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
7732                    break;
7733                case CMD_DELAYED_NETWORK_DISCONNECT:
7734                    if (!linkDebouncing && mWifiConfigManager.enableLinkDebouncing) {
7735
7736                        // Ignore if we are not debouncing
7737                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
7738                                + message.arg1);
7739                        return HANDLED;
7740                    } else {
7741                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
7742                                + message.arg1);
7743
7744                        linkDebouncing = false;
7745                        // If we are still debouncing while this message comes,
7746                        // it means we were not able to reconnect within the alloted time
7747                        // = LINK_FLAPPING_DEBOUNCE_MSEC
7748                        // and thus, trigger a real disconnect
7749                        handleNetworkDisconnect();
7750                        transitionTo(mDisconnectedState);
7751                    }
7752                    break;
7753                case CMD_ASSOCIATED_BSSID:
7754                    if ((String) message.obj == null) {
7755                        logw("Associated command w/o BSSID");
7756                        break;
7757                    }
7758                    mLastBssid = (String) message.obj;
7759                    if (mLastBssid != null && (mWifiInfo.getBSSID() == null
7760                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
7761                        mWifiInfo.setBSSID((String) message.obj);
7762                        sendNetworkStateChangeBroadcast(mLastBssid);
7763                    }
7764                    break;
7765                case CMD_START_RSSI_MONITORING_OFFLOAD:
7766                case CMD_RSSI_THRESHOLD_BREACH:
7767                    byte currRssi = (byte) message.arg1;
7768                    processRssiThreshold(currRssi, message.what);
7769                    break;
7770                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
7771                    stopRssiMonitoringOffload();
7772                    break;
7773                case CMD_RESET_SIM_NETWORKS:
7774                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
7775                        WifiConfiguration config =
7776                                mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
7777                        if (mWifiConfigManager.isSimConfig(config)) {
7778                            mWifiNative.disconnect();
7779                            transitionTo(mDisconnectingState);
7780                        }
7781                    }
7782                    /* allow parent state to reset data for other networks */
7783                    return NOT_HANDLED;
7784                default:
7785                    return NOT_HANDLED;
7786            }
7787
7788            return HANDLED;
7789        }
7790    }
7791
7792    class ObtainingIpState extends State {
7793        @Override
7794        public void enter() {
7795            if (DBG) {
7796                String key = "";
7797                if (getCurrentWifiConfiguration() != null) {
7798                    key = getCurrentWifiConfiguration().configKey();
7799                }
7800                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
7801                        + " " + key + " "
7802                        + " roam=" + mAutoRoaming
7803                        + " static=" + mWifiConfigManager.isUsingStaticIp(mLastNetworkId)
7804                        + " watchdog= " + obtainingIpWatchdogCount);
7805            }
7806
7807            // Reset link Debouncing, indicating we have successfully re-connected to the AP
7808            // We might still be roaming
7809            linkDebouncing = false;
7810
7811            // Send event to CM & network change broadcast
7812            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
7813
7814            // We must clear the config BSSID, as the wifi chipset may decide to roam
7815            // from this point on and having the BSSID specified in the network block would
7816            // cause the roam to fail and the device to disconnect.
7817            clearCurrentConfigBSSID("ObtainingIpAddress");
7818
7819            // Stop IpManager in case we're switching from DHCP to static
7820            // configuration or vice versa.
7821            //
7822            // TODO: Only ever enter this state the first time we connect to a
7823            // network, never on switching between static configuration and
7824            // DHCP. When we transition from static configuration to DHCP in
7825            // particular, we must tell ConnectivityService that we're
7826            // disconnected, because DHCP might take a long time during which
7827            // connectivity APIs such as getActiveNetworkInfo should not return
7828            // CONNECTED.
7829            stopIpManager();
7830
7831            mIpManager.setHttpProxy(mWifiConfigManager.getProxyProperties(mLastNetworkId));
7832            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
7833                mIpManager.setTcpBufferSizes(mTcpBufferSizes);
7834            }
7835
7836            if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
7837                final IpManager.ProvisioningConfiguration prov =
7838                        mIpManager.buildProvisioningConfiguration()
7839                            .withPreDhcpAction()
7840                            .build();
7841                mIpManager.startProvisioning(prov);
7842                obtainingIpWatchdogCount++;
7843                logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
7844                // Get Link layer stats so as we get fresh tx packet counters
7845                getWifiLinkLayerStats(true);
7846                sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
7847                        obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
7848            } else {
7849                StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(
7850                        mLastNetworkId);
7851                if (config.ipAddress == null) {
7852                    logd("Static IP lacks address");
7853                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
7854                } else {
7855                    final IpManager.ProvisioningConfiguration prov =
7856                            mIpManager.buildProvisioningConfiguration()
7857                                .withStaticConfiguration(config)
7858                                .build();
7859                    mIpManager.startProvisioning(prov);
7860                }
7861            }
7862        }
7863
7864        @Override
7865        public boolean processMessage(Message message) {
7866            logStateAndMessage(message, this);
7867
7868            switch(message.what) {
7869                case CMD_AUTO_CONNECT:
7870                case CMD_AUTO_ROAM:
7871                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7872                    break;
7873                case WifiManager.SAVE_NETWORK:
7874                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
7875                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
7876                    deferMessage(message);
7877                    break;
7878                    /* Defer any power mode changes since we must keep active power mode at DHCP */
7879
7880                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7881                    mWifiMetrics.endConnectionEvent(
7882                            WifiMetrics.ConnectionEvent.LLF_NETWORK_DISCONNECTION,
7883                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
7884                    return NOT_HANDLED;
7885                case CMD_SET_HIGH_PERF_MODE:
7886                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
7887                    deferMessage(message);
7888                    break;
7889                    /* Defer scan request since we should not switch to other channels at DHCP */
7890                case CMD_START_SCAN:
7891                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
7892                    deferMessage(message);
7893                    break;
7894                case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
7895                    if (message.arg1 == obtainingIpWatchdogCount) {
7896                        logd("ObtainingIpAddress: Watchdog Triggered, count="
7897                                + obtainingIpWatchdogCount);
7898                        handleIpConfigurationLost();
7899                        transitionTo(mDisconnectingState);
7900                        break;
7901                    }
7902                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7903                    break;
7904                default:
7905                    return NOT_HANDLED;
7906            }
7907            return HANDLED;
7908        }
7909    }
7910
7911    private void sendConnectedState() {
7912        // If this network was explicitly selected by the user, evaluate whether to call
7913        // explicitlySelected() so the system can treat it appropriately.
7914        WifiConfiguration config = getCurrentWifiConfiguration();
7915        if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
7916            boolean prompt =
7917                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
7918            if (DBG) {
7919                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
7920            }
7921            if (prompt) {
7922                // Selected by the user via Settings or QuickSettings. If this network has Internet
7923                // access, switch to it. Otherwise, switch to it only if the user confirms that they
7924                // really want to switch, or has already confirmed and selected "Don't ask again".
7925                if (DBG) {
7926                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
7927                }
7928                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
7929            }
7930        }
7931
7932        setNetworkDetailedState(DetailedState.CONNECTED);
7933        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
7934        sendNetworkStateChangeBroadcast(mLastBssid);
7935    }
7936
7937    class RoamingState extends State {
7938        boolean mAssociated;
7939        @Override
7940        public void enter() {
7941            if (DBG) {
7942                log("RoamingState Enter"
7943                        + " mScreenOn=" + mScreenOn );
7944            }
7945            setScanAlarm(false);
7946
7947            // Make sure we disconnect if roaming fails
7948            roamWatchdogCount++;
7949            logd("Start Roam Watchdog " + roamWatchdogCount);
7950            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
7951                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
7952            mAssociated = false;
7953        }
7954        @Override
7955        public boolean processMessage(Message message) {
7956            logStateAndMessage(message, this);
7957            WifiConfiguration config;
7958            switch (message.what) {
7959                case CMD_IP_CONFIGURATION_LOST:
7960                    config = getCurrentWifiConfiguration();
7961                    if (config != null) {
7962                        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
7963                        mWifiConfigManager.noteRoamingFailure(config,
7964                                WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
7965                    }
7966                    return NOT_HANDLED;
7967                case CMD_UNWANTED_NETWORK:
7968                    if (DBG) log("Roaming and CS doesnt want the network -> ignore");
7969                    return HANDLED;
7970                case CMD_SET_OPERATIONAL_MODE:
7971                    if (message.arg1 != CONNECT_MODE) {
7972                        deferMessage(message);
7973                    }
7974                    break;
7975                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7976                    /**
7977                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
7978                     * before NETWORK_DISCONNECTION_EVENT
7979                     * And there is an associated BSSID corresponding to our target BSSID, then
7980                     * we have missed the network disconnection, transition to mDisconnectedState
7981                     * and handle the rest of the events there.
7982                     */
7983                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
7984                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
7985                            || stateChangeResult.state == SupplicantState.INACTIVE
7986                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
7987                        if (DBG) {
7988                            log("STATE_CHANGE_EVENT in roaming state "
7989                                    + stateChangeResult.toString() );
7990                        }
7991                        if (stateChangeResult.BSSID != null
7992                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
7993                            handleNetworkDisconnect();
7994                            transitionTo(mDisconnectedState);
7995                        }
7996                    }
7997                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
7998                        // We completed the layer2 roaming part
7999                        mAssociated = true;
8000                        if (stateChangeResult.BSSID != null) {
8001                            mTargetRoamBSSID = (String) stateChangeResult.BSSID;
8002                        }
8003                    }
8004                    break;
8005                case CMD_ROAM_WATCHDOG_TIMER:
8006                    if (roamWatchdogCount == message.arg1) {
8007                        if (DBG) log("roaming watchdog! -> disconnect");
8008                        mRoamFailCount++;
8009                        handleNetworkDisconnect();
8010                        mWifiNative.disconnect();
8011                        transitionTo(mDisconnectedState);
8012                    }
8013                    break;
8014                case WifiMonitor.NETWORK_CONNECTION_EVENT:
8015                    if (mAssociated) {
8016                        if (DBG) log("roaming and Network connection established");
8017                        mLastNetworkId = message.arg1;
8018                        mLastBssid = (String) message.obj;
8019                        mWifiInfo.setBSSID(mLastBssid);
8020                        mWifiInfo.setNetworkId(mLastNetworkId);
8021                        mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(
8022                                mLastBssid, true);
8023                        sendNetworkStateChangeBroadcast(mLastBssid);
8024
8025                        // Successful framework roam! (probably)
8026                        mWifiMetrics.endConnectionEvent(
8027                                WifiMetrics.ConnectionEvent.LLF_NONE,
8028                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
8029                        // We used to transition to ObtainingIpState in an
8030                        // attempt to do DHCPv4 RENEWs on framework roams.
8031                        // DHCP can take too long to time out, and we now rely
8032                        // upon IpManager's use of IpReachabilityMonitor to
8033                        // confirm our current network configuration.
8034                        //
8035                        // mIpManager.confirmConfiguration() is called within
8036                        // the handling of SupplicantState.COMPLETED.
8037                        transitionTo(mConnectedState);
8038                    } else {
8039                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8040                    }
8041                    break;
8042                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8043                    // Throw away but only if it corresponds to the network we're roaming to
8044                    String bssid = (String) message.obj;
8045                    if (true) {
8046                        String target = "";
8047                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
8048                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
8049                                + " BSSID=" + bssid
8050                                + " target=" + target);
8051                    }
8052                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
8053                        handleNetworkDisconnect();
8054                        transitionTo(mDisconnectedState);
8055                    }
8056                    break;
8057                case WifiMonitor.SSID_TEMP_DISABLED:
8058                    // Auth error while roaming
8059                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
8060                            + " id=" + Integer.toString(message.arg1)
8061                            + " isRoaming=" + isRoaming()
8062                            + " roam=" + mAutoRoaming);
8063                    if (message.arg1 == mLastNetworkId) {
8064                        config = getCurrentWifiConfiguration();
8065                        if (config != null) {
8066                            mWifiLogger.captureBugReportData(
8067                                    WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
8068                            mWifiConfigManager.noteRoamingFailure(config,
8069                                    WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
8070                        }
8071                        handleNetworkDisconnect();
8072                        transitionTo(mDisconnectingState);
8073                    }
8074                    return NOT_HANDLED;
8075                case CMD_START_SCAN:
8076                    deferMessage(message);
8077                    break;
8078                default:
8079                    return NOT_HANDLED;
8080            }
8081            return HANDLED;
8082        }
8083
8084        @Override
8085        public void exit() {
8086            logd("WifiStateMachine: Leaving Roaming state");
8087        }
8088    }
8089
8090    class ConnectedState extends State {
8091        @Override
8092        public void enter() {
8093            String address;
8094            updateDefaultRouteMacAddress(1000);
8095            if (DBG) {
8096                log("Enter ConnectedState "
8097                       + " mScreenOn=" + mScreenOn
8098                       + " scanperiod="
8099                       + Integer.toString(
8100                            mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get())
8101                       + " useGscan=" + mHalBasedPnoDriverSupported + "/"
8102                        + mWifiConfigManager.enableHalBasedPno.get()
8103                        + " mHalBasedPnoEnableInDevSettings " + mHalBasedPnoEnableInDevSettings);
8104            }
8105            if (mScreenOn
8106                    && getEnableAutoJoinWhenAssociated()) {
8107                if (useHalBasedAutoJoinOffload()) {
8108                    startGScanConnectedModeOffload("connectedEnter");
8109                } else {
8110                    // restart scan alarm
8111                    startDelayedScan(mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get(),
8112                            null, null);
8113                }
8114            }
8115            registerConnected();
8116            lastConnectAttemptTimestamp = 0;
8117            targetWificonfiguration = null;
8118            // Paranoia
8119            linkDebouncing = false;
8120
8121            // Not roaming anymore
8122            mAutoRoaming = false;
8123
8124            if (testNetworkDisconnect) {
8125                testNetworkDisconnectCounter++;
8126                logd("ConnectedState Enter start disconnect test " +
8127                        testNetworkDisconnectCounter);
8128                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
8129                        testNetworkDisconnectCounter, 0), 15000);
8130            }
8131
8132            // Reenable all networks, allow for hidden networks to be scanned
8133            mWifiConfigManager.enableAllNetworks();
8134
8135            mLastDriverRoamAttempt = 0;
8136            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
8137        }
8138        @Override
8139        public boolean processMessage(Message message) {
8140            WifiConfiguration config = null;
8141            logStateAndMessage(message, this);
8142
8143            switch (message.what) {
8144                case CMD_RESTART_AUTOJOIN_OFFLOAD:
8145                    if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
8146                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8147                        return HANDLED;
8148                    }
8149                    /* If we are still in Disconnected state after having discovered a valid
8150                     * network this means autojoin didnt managed to associate to the network,
8151                     * then restart PNO so as we will try associating to it again.
8152                     */
8153                    if (useHalBasedAutoJoinOffload()) {
8154                        if (mGScanStartTimeMilli == 0) {
8155                            // If offload is not started, then start it...
8156                            startGScanConnectedModeOffload("connectedRestart");
8157                        } else {
8158                            // If offload is already started, then check if we need to increase
8159                            // the scan period and restart the Gscan
8160                            long now = System.currentTimeMillis();
8161                            if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
8162                                    && ((now - mGScanStartTimeMilli)
8163                                    > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
8164                                && (mGScanPeriodMilli
8165                                    < mWifiConfigManager
8166                                    .wifiDisconnectedLongScanIntervalMilli.get()))
8167                            {
8168                                startConnectedGScan("Connected restart gscan");
8169                            }
8170                        }
8171                    }
8172                    break;
8173                case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
8174                    updateAssociatedScanPermission();
8175                    break;
8176                case CMD_UNWANTED_NETWORK:
8177                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
8178                        mWifiConfigManager.handleBadNetworkDisconnectReport(
8179                                mLastNetworkId, mWifiInfo);
8180                        mWifiNative.disconnect();
8181                        transitionTo(mDisconnectingState);
8182                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
8183                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
8184                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
8185                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
8186                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
8187                        config = getCurrentWifiConfiguration();
8188                        if (config != null) {
8189                            // Disable autojoin
8190                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
8191                                config.validatedInternetAccess = false;
8192                                // Clear last-selected status, as being last-selected also avoids
8193                                // disabling auto-join.
8194                                if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
8195                                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(
8196                                        WifiConfiguration.INVALID_NETWORK_ID);
8197                                }
8198                                mWifiConfigManager.updateNetworkSelectionStatus(config,
8199                                        WifiConfiguration.NetworkSelectionStatus
8200                                        .DISABLED_NO_INTERNET);
8201                            }
8202                            config.numNoInternetAccessReports += 1;
8203                            mWifiConfigManager.writeKnownNetworkHistory();
8204                        }
8205                    }
8206                    return HANDLED;
8207                case CMD_NETWORK_STATUS:
8208                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
8209                        config = getCurrentWifiConfiguration();
8210                        if (config != null) {
8211                            // re-enable autojoin
8212                            config.numNoInternetAccessReports = 0;
8213                            config.validatedInternetAccess = true;
8214                            mWifiConfigManager.writeKnownNetworkHistory();
8215                        }
8216                    }
8217                    return HANDLED;
8218                case CMD_ACCEPT_UNVALIDATED:
8219                    boolean accept = (message.arg1 != 0);
8220                    config = getCurrentWifiConfiguration();
8221                    if (config != null) {
8222                        config.noInternetAccessExpected = accept;
8223                    }
8224                    return HANDLED;
8225                case CMD_TEST_NETWORK_DISCONNECT:
8226                    // Force a disconnect
8227                    if (message.arg1 == testNetworkDisconnectCounter) {
8228                        mWifiNative.disconnect();
8229                    }
8230                    break;
8231                case CMD_ASSOCIATED_BSSID:
8232                    // ASSOCIATING to a new BSSID while already connected, indicates
8233                    // that driver is roaming
8234                    mLastDriverRoamAttempt = System.currentTimeMillis();
8235                    return NOT_HANDLED;
8236                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8237                    long lastRoam = 0;
8238                    mWifiMetrics.endConnectionEvent(
8239                            WifiMetrics.ConnectionEvent.LLF_NETWORK_DISCONNECTION,
8240                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
8241                    if (mLastDriverRoamAttempt != 0) {
8242                        // Calculate time since last driver roam attempt
8243                        lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
8244                        mLastDriverRoamAttempt = 0;
8245                    }
8246                    if (unexpectedDisconnectedReason(message.arg2)) {
8247                        mWifiLogger.captureBugReportData(
8248                                WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
8249                    }
8250                    config = getCurrentWifiConfiguration();
8251                    if (mScreenOn
8252                            && !linkDebouncing
8253                            && config != null
8254                            && config.getNetworkSelectionStatus().isNetworkEnabled()
8255                            && !mWifiConfigManager.isLastSelectedConfiguration(config)
8256                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
8257                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
8258                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
8259                                    && mWifiInfo.getRssi() >
8260                                    WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
8261                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
8262                                    && mWifiInfo.getRssi() >
8263                                    mWifiConfigManager.thresholdQualifiedRssi5.get()))) {
8264                        // Start de-bouncing the L2 disconnection:
8265                        // this L2 disconnection might be spurious.
8266                        // Hence we allow 7 seconds for the state machine to try
8267                        // to reconnect, go thru the
8268                        // roaming cycle and enter Obtaining IP address
8269                        // before signalling the disconnect to ConnectivityService and L3
8270                        startScanForConfiguration(getCurrentWifiConfiguration(), false);
8271                        linkDebouncing = true;
8272
8273                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
8274                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
8275                        if (DBG) {
8276                            log("NETWORK_DISCONNECTION_EVENT in connected state"
8277                                    + " BSSID=" + mWifiInfo.getBSSID()
8278                                    + " RSSI=" + mWifiInfo.getRssi()
8279                                    + " freq=" + mWifiInfo.getFrequency()
8280                                    + " reason=" + message.arg2
8281                                    + " -> debounce");
8282                        }
8283                        return HANDLED;
8284                    } else {
8285                        if (DBG) {
8286                            log("NETWORK_DISCONNECTION_EVENT in connected state"
8287                                    + " BSSID=" + mWifiInfo.getBSSID()
8288                                    + " RSSI=" + mWifiInfo.getRssi()
8289                                    + " freq=" + mWifiInfo.getFrequency()
8290                                    + " was debouncing=" + linkDebouncing
8291                                    + " reason=" + message.arg2
8292                                    + " Network Selection Status=" + (config == null ? "Unavailable"
8293                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
8294                        }
8295                    }
8296                    break;
8297                case CMD_AUTO_ROAM:
8298                    // Clear the driver roam indication since we are attempting a framework roam
8299                    mLastDriverRoamAttempt = 0;
8300
8301                    /*<TODO> 2016-02-24
8302                        Fix CMD_AUTO_ROAM to use the candidate (message.arg1) networkID, rather than
8303                        the old networkID.
8304                        The current code only handles roaming between BSSIDs on the same networkID,
8305                        and will break for roams between different (but linked) networkIDs. This
8306                        case occurs for DBDC roaming, and the CMD_AUTO_ROAM sent due to it will
8307                        fail.
8308                    */
8309                    /* Connect command coming from auto-join */
8310                    ScanResult candidate = (ScanResult)message.obj;
8311                    String bssid = "any";
8312                    if (candidate != null) {
8313                        bssid = candidate.BSSID;
8314                    }
8315                    int netId = mLastNetworkId;
8316                    config = getCurrentWifiConfiguration();
8317
8318
8319                    if (config == null) {
8320                        loge("AUTO_ROAM and no config, bail out...");
8321                        break;
8322                    }
8323
8324                    logd("CMD_AUTO_ROAM sup state "
8325                            + mSupplicantStateTracker.getSupplicantStateName()
8326                            + " my state " + getCurrentState().getName()
8327                            + " nid=" + Integer.toString(netId)
8328                            + " config " + config.configKey()
8329                            + " roam=" + Integer.toString(message.arg2)
8330                            + " to " + bssid
8331                            + " targetRoamBSSID " + mTargetRoamBSSID);
8332
8333                    setTargetBssid(config, bssid);
8334                    mTargetNetworkId = netId;
8335                    mWifiMetrics.startConnectionEvent(config,
8336                            WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
8337                    /* <TODO> 2016-02-24
8338                        Detect DBDC (2.4 <-> 5Ghz, same AP) roaming events, once CMD_AUTO_ROAM
8339                        has been fixed to handle them correctly:
8340                            mWifiMetrics.setConnectionEventRoamType(
8341                                  WifiMetricsProto.ConnectionEvent.ROAM_DBDC);
8342                            Handy statements:
8343                                ABSSID.regionMatches(true, 0, BBSSID, 0, 16) //BSSID matching
8344                                currentConfig.isLinked(config) //check the configs are linked
8345                    */
8346                    if (deferForUserInput(message, netId, false)) {
8347                        mWifiMetrics.endConnectionEvent(
8348                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
8349                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
8350                        break;
8351                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
8352                            WifiConfiguration.USER_BANNED) {
8353                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8354                                WifiManager.NOT_AUTHORIZED);
8355                        mWifiMetrics.endConnectionEvent(
8356                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
8357                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
8358                        break;
8359                    }
8360
8361                    boolean ret = false;
8362                    if (mLastNetworkId != netId) {
8363                        if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
8364                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
8365                            ret = true;
8366                        }
8367                    } else {
8368                        ret = mWifiNative.reassociate();
8369                    }
8370                    if (ret) {
8371                        lastConnectAttemptTimestamp = System.currentTimeMillis();
8372                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
8373
8374                        // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
8375                        mAutoRoaming = true;
8376                        transitionTo(mRoamingState);
8377
8378                    } else {
8379                        loge("Failed to connect config: " + config + " netId: " + netId);
8380                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8381                                WifiManager.ERROR);
8382                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
8383                        mWifiMetrics.endConnectionEvent(
8384                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
8385                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
8386                        break;
8387                    }
8388                    break;
8389                case CMD_START_IP_PACKET_OFFLOAD: {
8390                        int slot = message.arg1;
8391                        int intervalSeconds = message.arg2;
8392                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
8393                        byte[] dstMac;
8394                        try {
8395                            InetAddress gateway = RouteInfo.selectBestRoute(
8396                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
8397                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
8398                            dstMac = macAddressFromString(dstMacStr);
8399                        } catch (NullPointerException|IllegalArgumentException e) {
8400                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
8401                            mNetworkAgent.onPacketKeepaliveEvent(slot,
8402                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
8403                            break;
8404                        }
8405                        pkt.dstMac = dstMac;
8406                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
8407                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
8408                        break;
8409                    }
8410                default:
8411                    return NOT_HANDLED;
8412            }
8413            return HANDLED;
8414        }
8415
8416        @Override
8417        public void exit() {
8418            logd("WifiStateMachine: Leaving Connected state");
8419            setScanAlarm(false);
8420            mLastDriverRoamAttempt = 0;
8421            mWhiteListedSsids = null;
8422        }
8423    }
8424
8425    class DisconnectingState extends State {
8426
8427        @Override
8428        public void enter() {
8429
8430            if (DBG) {
8431                logd(" Enter DisconnectingState State scan interval "
8432                        + mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get()
8433                        + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
8434                        + " screenOn=" + mScreenOn);
8435            }
8436
8437            // Make sure we disconnect: we enter this state prior to connecting to a new
8438            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
8439            // event which in this case will be indicating that supplicant started to associate.
8440            // In some cases supplicant doesn't ignore the connect requests (it might not
8441            // find the target SSID in its cache),
8442            // Therefore we end up stuck that state, hence the need for the watchdog.
8443            disconnectingWatchdogCount++;
8444            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
8445            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
8446                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
8447        }
8448
8449        @Override
8450        public boolean processMessage(Message message) {
8451            logStateAndMessage(message, this);
8452            switch (message.what) {
8453                case CMD_SET_OPERATIONAL_MODE:
8454                    if (message.arg1 != CONNECT_MODE) {
8455                        deferMessage(message);
8456                    }
8457                    break;
8458                case CMD_START_SCAN:
8459                    deferMessage(message);
8460                    return HANDLED;
8461                case CMD_DISCONNECTING_WATCHDOG_TIMER:
8462                    if (disconnectingWatchdogCount == message.arg1) {
8463                        if (DBG) log("disconnecting watchdog! -> disconnect");
8464                        handleNetworkDisconnect();
8465                        transitionTo(mDisconnectedState);
8466                    }
8467                    break;
8468                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8469                    /**
8470                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
8471                     * we have missed the network disconnection, transition to mDisconnectedState
8472                     * and handle the rest of the events there
8473                     */
8474                    deferMessage(message);
8475                    handleNetworkDisconnect();
8476                    transitionTo(mDisconnectedState);
8477                    break;
8478                default:
8479                    return NOT_HANDLED;
8480            }
8481            return HANDLED;
8482        }
8483    }
8484
8485    class DisconnectedState extends State {
8486        @Override
8487        public void enter() {
8488            // We dont scan frequently if this is a temporary disconnect
8489            // due to p2p
8490            if (mTemporarilyDisconnectWifi) {
8491                mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
8492                return;
8493            }
8494
8495            if (DBG) {
8496                logd(" Enter DisconnectedState scan interval "
8497                        + mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get()
8498                        + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
8499                        + " screenOn=" + mScreenOn
8500                        + " useGscan=" + mHalBasedPnoDriverSupported + "/"
8501                        + mWifiConfigManager.enableHalBasedPno.get());
8502            }
8503
8504            /** clear the roaming state, if we were roaming, we failed */
8505            mAutoRoaming = false;
8506
8507            if (useHalBasedAutoJoinOffload()) {
8508                startGScanDisconnectedModeOffload("disconnectedEnter");
8509            } else {
8510                if (mScreenOn) {
8511                    /**
8512                     * screen lit and => start scan immediately
8513                     */
8514                    startScan(UNKNOWN_SCAN_SOURCE, 0, null, null);
8515                } else {
8516                    /**
8517                     * screen dark and PNO supported => scan alarm disabled
8518                     */
8519                    if (mBackgroundScanSupported) {
8520                        /* If a regular scan result is pending, do not initiate background
8521                         * scan until the scan results are returned. This is needed because
8522                        * initiating a background scan will cancel the regular scan and
8523                        * scan results will not be returned until background scanning is
8524                        * cleared
8525                        */
8526                        if (!mIsScanOngoing) {
8527                            enableBackgroundScan(true);
8528                        }
8529                    } else {
8530                        setScanAlarm(true);
8531                    }
8532                }
8533            }
8534
8535            /**
8536             * If we have no networks saved, the supplicant stops doing the periodic scan.
8537             * The scans are useful to notify the user of the presence of an open network.
8538             * Note that these are not wake up scans.
8539             */
8540            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
8541                    && mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8542                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8543                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8544            }
8545
8546            mDisconnectedTimeStamp = System.currentTimeMillis();
8547            mDisconnectedPnoAlarmCount = 0;
8548        }
8549        @Override
8550        public boolean processMessage(Message message) {
8551            boolean ret = HANDLED;
8552
8553            logStateAndMessage(message, this);
8554
8555            switch (message.what) {
8556                case CMD_NO_NETWORKS_PERIODIC_SCAN:
8557                    if (mP2pConnected.get()) break;
8558                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
8559                            mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8560                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
8561                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8562                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8563                    }
8564                    break;
8565                case WifiManager.FORGET_NETWORK:
8566                case CMD_REMOVE_NETWORK:
8567                case CMD_REMOVE_APP_CONFIGURATIONS:
8568                case CMD_REMOVE_USER_CONFIGURATIONS:
8569                    // Set up a delayed message here. After the forget/remove is handled
8570                    // the handled delayed message will determine if there is a need to
8571                    // scan and continue
8572                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8573                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8574                    ret = NOT_HANDLED;
8575                    break;
8576                case CMD_SET_OPERATIONAL_MODE:
8577                    if (message.arg1 != CONNECT_MODE) {
8578                        mOperationalMode = message.arg1;
8579                        mWifiConfigManager.disableAllNetworksNative();
8580                        if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
8581                            mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
8582                            setWifiState(WIFI_STATE_DISABLED);
8583                        }
8584                        transitionTo(mScanModeState);
8585                    }
8586                    mWifiConfigManager.
8587                            setAndEnableLastSelectedConfiguration(
8588                                    WifiConfiguration.INVALID_NETWORK_ID);
8589                    break;
8590                    /* Ignore network disconnect */
8591                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8592                    // Interpret this as an L2 connection failure
8593                    break;
8594                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8595                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
8596                    if (DBG) {
8597                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
8598                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
8599                                + " debouncing=" + linkDebouncing);
8600                    }
8601                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
8602                    /* ConnectModeState does the rest of the handling */
8603                    ret = NOT_HANDLED;
8604                    break;
8605                case CMD_START_SCAN:
8606                    if (!checkOrDeferScanAllowed(message)) {
8607                        // The scan request was rescheduled
8608                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
8609                        return HANDLED;
8610                    }
8611                    if (message.arg1 == SCAN_ALARM_SOURCE) {
8612                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
8613                        // not be processed) and restart the scan
8614                        int period =
8615                                mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get();
8616                        if (mP2pConnected.get()) {
8617                            period = (int) mFacade.getLongSetting(mContext,
8618                                    Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
8619                                    period);
8620                        }
8621                        if (!checkAndRestartDelayedScan(message.arg2,
8622                                true, period, null, null)) {
8623                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8624                            logd("Disconnected CMD_START_SCAN source "
8625                                    + message.arg1
8626                                    + " " + message.arg2 + ", " + mDelayedScanCounter
8627                                    + " -> obsolete");
8628                            return HANDLED;
8629                        }
8630                        /* Disable background scan temporarily during a regular scan */
8631                        enableBackgroundScan(false);
8632                        handleScanRequest(message);
8633                        ret = HANDLED;
8634                    } else {
8635
8636                        /*
8637                         * The SCAN request is not handled in this state and
8638                         * would eventually might/will get handled in the
8639                         * parent's state. The PNO, if already enabled had to
8640                         * get disabled before the SCAN trigger. Hence, stop
8641                         * the PNO if already enabled in this state, though the
8642                         * SCAN request is not handled(PNO disable before the
8643                         * SCAN trigger in any other state is not the right
8644                         * place to issue).
8645                         */
8646
8647                        enableBackgroundScan(false);
8648                        ret = NOT_HANDLED;
8649                    }
8650                    break;
8651                case CMD_RESTART_AUTOJOIN_OFFLOAD:
8652                    if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
8653                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8654                        return HANDLED;
8655                    }
8656                    /* If we are still in Disconnected state after having discovered a valid
8657                     * network this means autojoin didnt managed to associate to the network,
8658                     * then restart PNO so as we will try associating to it again.
8659                     */
8660                    if (useHalBasedAutoJoinOffload()) {
8661                        if (mGScanStartTimeMilli == 0) {
8662                            // If offload is not started, then start it...
8663                            startGScanDisconnectedModeOffload("disconnectedRestart");
8664                        } else {
8665                            // If offload is already started, then check if we need to increase
8666                            // the scan period and restart the Gscan
8667                            long now = System.currentTimeMillis();
8668                            if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
8669                                    && ((now - mGScanStartTimeMilli)
8670                                    > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
8671                                    && (mGScanPeriodMilli
8672                                    < mWifiConfigManager
8673                                    .wifiDisconnectedLongScanIntervalMilli.get()))
8674                            {
8675                                startDisconnectedGScan("disconnected restart gscan");
8676                            }
8677                        }
8678                    } else {
8679                        // If we are still disconnected for a short while after having found a
8680                        // network thru PNO, then something went wrong, and for some reason we
8681                        // couldn't join this network.
8682                        // It might be due to a SW bug in supplicant or the wifi stack, or an
8683                        // interoperability issue, or we try to join a bad bss and failed
8684                        // In that case we want to restart pno so as to make sure that we will
8685                        // attempt again to join that network.
8686                        if (!mScreenOn && !mIsScanOngoing && mBackgroundScanSupported) {
8687                            enableBackgroundScan(false);
8688                            enableBackgroundScan(true);
8689                        }
8690                        return HANDLED;
8691                    }
8692                    break;
8693                case WifiMonitor.SCAN_RESULTS_EVENT:
8694                case WifiMonitor.SCAN_FAILED_EVENT:
8695                    /* Re-enable background scan when a pending scan result is received */
8696                    if (!mScreenOn && mIsScanOngoing
8697                            && mBackgroundScanSupported
8698                            && !useHalBasedAutoJoinOffload()) {
8699                        enableBackgroundScan(true);
8700                    } else if (!mScreenOn
8701                            && !mIsScanOngoing
8702                            && mBackgroundScanSupported
8703                            && !useHalBasedAutoJoinOffload()) {
8704                        // We receive scan results from legacy PNO, hence restart the PNO alarm
8705                        int delay;
8706                        if (mDisconnectedPnoAlarmCount < 1) {
8707                            delay = 30 * 1000;
8708                        } else if (mDisconnectedPnoAlarmCount < 3) {
8709                            delay = 60 * 1000;
8710                        } else {
8711                            delay = 360 * 1000;
8712                        }
8713                        mDisconnectedPnoAlarmCount++;
8714                        if (DBG) {
8715                            logd("Starting PNO alarm " + delay);
8716                        }
8717                        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
8718                                System.currentTimeMillis() + delay,
8719                                mPnoIntent);
8720                    }
8721                    /* Handled in parent state */
8722                    ret = NOT_HANDLED;
8723                    break;
8724                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
8725                    NetworkInfo info = (NetworkInfo) message.obj;
8726                    mP2pConnected.set(info.isConnected());
8727                    if (mP2pConnected.get()) {
8728                        int defaultInterval = mContext.getResources().getInteger(
8729                                R.integer.config_wifi_scan_interval_p2p_connected);
8730                        long scanIntervalMs = mFacade.getLongSetting(mContext,
8731                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
8732                                defaultInterval);
8733                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
8734                    } else if (mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8735                        if (DBG) log("Turn on scanning after p2p disconnected");
8736                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8737                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8738                    } else {
8739                        // If P2P is not connected and there are saved networks, then restart
8740                        // scanning at the normal period. This is necessary because scanning might
8741                        // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
8742                        // was set to zero.
8743                        if (useHalBasedAutoJoinOffload()) {
8744                            startGScanDisconnectedModeOffload("p2pRestart");
8745                        } else {
8746                            startDelayedScan(
8747                                    mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get(),
8748                                    null, null);
8749                        }
8750                    }
8751                    break;
8752                case CMD_RECONNECT:
8753                case CMD_REASSOCIATE:
8754                    if (mTemporarilyDisconnectWifi) {
8755                        // Drop a third party reconnect/reassociate if STA is
8756                        // temporarily disconnected for p2p
8757                        break;
8758                    } else {
8759                        // ConnectModeState handles it
8760                        ret = NOT_HANDLED;
8761                    }
8762                    break;
8763                case CMD_SCREEN_STATE_CHANGED:
8764                    handleScreenStateChanged(message.arg1 != 0);
8765                    break;
8766                default:
8767                    ret = NOT_HANDLED;
8768            }
8769            return ret;
8770        }
8771
8772        @Override
8773        public void exit() {
8774            mDisconnectedPnoAlarmCount = 0;
8775            /* No need for a background scan upon exit from a disconnected state */
8776            enableBackgroundScan(false);
8777            setScanAlarm(false);
8778            mAlarmManager.cancel(mPnoIntent);
8779        }
8780    }
8781
8782    class WpsRunningState extends State {
8783        // Tracks the source to provide a reply
8784        private Message mSourceMessage;
8785        @Override
8786        public void enter() {
8787            mSourceMessage = Message.obtain(getCurrentMessage());
8788        }
8789        @Override
8790        public boolean processMessage(Message message) {
8791            logStateAndMessage(message, this);
8792
8793            switch (message.what) {
8794                case WifiMonitor.WPS_SUCCESS_EVENT:
8795                    // Ignore intermediate success, wait for full connection
8796                    break;
8797                case WifiMonitor.NETWORK_CONNECTION_EVENT:
8798                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
8799                    mSourceMessage.recycle();
8800                    mSourceMessage = null;
8801                    deferMessage(message);
8802                    transitionTo(mDisconnectedState);
8803                    break;
8804                case WifiMonitor.WPS_OVERLAP_EVENT:
8805                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
8806                            WifiManager.WPS_OVERLAP_ERROR);
8807                    mSourceMessage.recycle();
8808                    mSourceMessage = null;
8809                    transitionTo(mDisconnectedState);
8810                    break;
8811                case WifiMonitor.WPS_FAIL_EVENT:
8812                    // Arg1 has the reason for the failure
8813                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
8814                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
8815                        mSourceMessage.recycle();
8816                        mSourceMessage = null;
8817                        transitionTo(mDisconnectedState);
8818                    } else {
8819                        if (DBG) log("Ignore unspecified fail event during WPS connection");
8820                    }
8821                    break;
8822                case WifiMonitor.WPS_TIMEOUT_EVENT:
8823                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
8824                            WifiManager.WPS_TIMED_OUT);
8825                    mSourceMessage.recycle();
8826                    mSourceMessage = null;
8827                    transitionTo(mDisconnectedState);
8828                    break;
8829                case WifiManager.START_WPS:
8830                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
8831                    break;
8832                case WifiManager.CANCEL_WPS:
8833                    if (mWifiNative.cancelWps()) {
8834                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
8835                    } else {
8836                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
8837                    }
8838                    transitionTo(mDisconnectedState);
8839                    break;
8840                /**
8841                 * Defer all commands that can cause connections to a different network
8842                 * or put the state machine out of connect mode
8843                 */
8844                case CMD_STOP_DRIVER:
8845                case CMD_SET_OPERATIONAL_MODE:
8846                case WifiManager.CONNECT_NETWORK:
8847                case CMD_ENABLE_NETWORK:
8848                case CMD_RECONNECT:
8849                case CMD_REASSOCIATE:
8850                case CMD_ENABLE_ALL_NETWORKS:
8851                    deferMessage(message);
8852                    break;
8853                case CMD_AUTO_CONNECT:
8854                case CMD_AUTO_ROAM:
8855                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8856                    return HANDLED;
8857                case CMD_START_SCAN:
8858                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8859                    return HANDLED;
8860                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8861                    if (DBG) log("Network connection lost");
8862                    handleNetworkDisconnect();
8863                    break;
8864                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
8865                    if (DBG) log("Ignore Assoc reject event during WPS Connection");
8866                    break;
8867                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
8868                    // Disregard auth failure events during WPS connection. The
8869                    // EAP sequence is retried several times, and there might be
8870                    // failures (especially for wps pin). We will get a WPS_XXX
8871                    // event at the end of the sequence anyway.
8872                    if (DBG) log("Ignore auth failure during WPS connection");
8873                    break;
8874                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8875                    // Throw away supplicant state changes when WPS is running.
8876                    // We will start getting supplicant state changes once we get
8877                    // a WPS success or failure
8878                    break;
8879                default:
8880                    return NOT_HANDLED;
8881            }
8882            return HANDLED;
8883        }
8884
8885        @Override
8886        public void exit() {
8887            mWifiConfigManager.enableAllNetworks();
8888            mWifiConfigManager.loadConfiguredNetworks();
8889        }
8890    }
8891
8892    class SoftApState extends State {
8893        private SoftApManager mSoftApManager;
8894
8895        private class SoftApListener implements SoftApManager.Listener {
8896            @Override
8897            public void onStateChanged(int state, int reason) {
8898                if (state == WIFI_AP_STATE_DISABLED) {
8899                    sendMessage(CMD_AP_STOPPED);
8900                } else if (state == WIFI_AP_STATE_FAILED) {
8901                    sendMessage(CMD_START_AP_FAILURE);
8902                }
8903
8904                setWifiApState(state, reason);
8905            }
8906        }
8907
8908        @Override
8909        public void enter() {
8910            final Message message = getCurrentMessage();
8911            if (message.what == CMD_START_AP) {
8912                WifiConfiguration config = (WifiConfiguration) message.obj;
8913
8914                if (config == null) {
8915                    /**
8916                     * Configuration not provided in the command, fallback to use the current
8917                     * configuration.
8918                     */
8919                    config = mWifiApConfigStore.getApConfiguration();
8920                } else {
8921                    /* Update AP configuration. */
8922                    mWifiApConfigStore.setApConfiguration(config);
8923                }
8924
8925                checkAndSetConnectivityInstance();
8926                mSoftApManager = mFacade.makeSoftApManager(
8927                        mContext, getHandler().getLooper(), mWifiNative, mNwService,
8928                        mCm, getCurrentCountryCode(),
8929                        mWifiApConfigStore.getAllowed2GChannel(),
8930                        new SoftApListener());
8931                mSoftApManager.start(config);
8932            } else {
8933                throw new RuntimeException("Illegal transition to SoftApState: " + message);
8934            }
8935        }
8936
8937        @Override
8938        public void exit() {
8939            mSoftApManager = null;
8940        }
8941
8942        @Override
8943        public boolean processMessage(Message message) {
8944            logStateAndMessage(message, this);
8945
8946            switch(message.what) {
8947                case CMD_START_AP:
8948                    /* Ignore start command when it is starting/started. */
8949                    break;
8950                case CMD_STOP_AP:
8951                    mSoftApManager.stop();
8952                    break;
8953                case CMD_START_AP_FAILURE:
8954                    transitionTo(mInitialState);
8955                    break;
8956                case CMD_AP_STOPPED:
8957                    transitionTo(mInitialState);
8958                    break;
8959                default:
8960                    return NOT_HANDLED;
8961            }
8962            return HANDLED;
8963        }
8964    }
8965
8966    /**
8967     * State machine initiated requests can have replyTo set to null indicating
8968     * there are no recepients, we ignore those reply actions.
8969     */
8970    private void replyToMessage(Message msg, int what) {
8971        if (msg.replyTo == null) return;
8972        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
8973        mReplyChannel.replyToMessage(msg, dstMsg);
8974    }
8975
8976    private void replyToMessage(Message msg, int what, int arg1) {
8977        if (msg.replyTo == null) return;
8978        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
8979        dstMsg.arg1 = arg1;
8980        mReplyChannel.replyToMessage(msg, dstMsg);
8981    }
8982
8983    private void replyToMessage(Message msg, int what, Object obj) {
8984        if (msg.replyTo == null) return;
8985        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
8986        dstMsg.obj = obj;
8987        mReplyChannel.replyToMessage(msg, dstMsg);
8988    }
8989
8990    /**
8991     * arg2 on the source message has a unique id that needs to be retained in replies
8992     * to match the request
8993     * <p>see WifiManager for details
8994     */
8995    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
8996        Message msg = Message.obtain();
8997        msg.what = what;
8998        msg.arg2 = srcMsg.arg2;
8999        return msg;
9000    }
9001
9002    /**
9003     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
9004     * @param msg Must have a WifiConfiguration obj to succeed
9005     */
9006    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
9007            WifiConfiguration config) {
9008        if (config != null && config.preSharedKey != null) {
9009            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
9010            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
9011            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
9012                    wifiCredentialEventType);
9013            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
9014                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
9015        }
9016    }
9017
9018    private static int parseHex(char ch) {
9019        if ('0' <= ch && ch <= '9') {
9020            return ch - '0';
9021        } else if ('a' <= ch && ch <= 'f') {
9022            return ch - 'a' + 10;
9023        } else if ('A' <= ch && ch <= 'F') {
9024            return ch - 'A' + 10;
9025        } else {
9026            throw new NumberFormatException("" + ch + " is not a valid hex digit");
9027        }
9028    }
9029
9030    private byte[] parseHex(String hex) {
9031        /* This only works for good input; don't throw bad data at it */
9032        if (hex == null) {
9033            return new byte[0];
9034        }
9035
9036        if (hex.length() % 2 != 0) {
9037            throw new NumberFormatException(hex + " is not a valid hex string");
9038        }
9039
9040        byte[] result = new byte[(hex.length())/2 + 1];
9041        result[0] = (byte) ((hex.length())/2);
9042        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
9043            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
9044            byte b = (byte) (val & 0xFF);
9045            result[j] = b;
9046        }
9047
9048        return result;
9049    }
9050
9051    private static String makeHex(byte[] bytes) {
9052        StringBuilder sb = new StringBuilder();
9053        for (byte b : bytes) {
9054            sb.append(String.format("%02x", b));
9055        }
9056        return sb.toString();
9057    }
9058
9059    private static String makeHex(byte[] bytes, int from, int len) {
9060        StringBuilder sb = new StringBuilder();
9061        for (int i = 0; i < len; i++) {
9062            sb.append(String.format("%02x", bytes[from+i]));
9063        }
9064        return sb.toString();
9065    }
9066
9067    private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
9068
9069        int len = array1.length + array2.length + array3.length;
9070
9071        if (array1.length != 0) {
9072            len++;                      /* add another byte for size */
9073        }
9074
9075        if (array2.length != 0) {
9076            len++;                      /* add another byte for size */
9077        }
9078
9079        if (array3.length != 0) {
9080            len++;                      /* add another byte for size */
9081        }
9082
9083        byte[] result = new byte[len];
9084
9085        int index = 0;
9086        if (array1.length != 0) {
9087            result[index] = (byte) (array1.length & 0xFF);
9088            index++;
9089            for (byte b : array1) {
9090                result[index] = b;
9091                index++;
9092            }
9093        }
9094
9095        if (array2.length != 0) {
9096            result[index] = (byte) (array2.length & 0xFF);
9097            index++;
9098            for (byte b : array2) {
9099                result[index] = b;
9100                index++;
9101            }
9102        }
9103
9104        if (array3.length != 0) {
9105            result[index] = (byte) (array3.length & 0xFF);
9106            index++;
9107            for (byte b : array3) {
9108                result[index] = b;
9109                index++;
9110            }
9111        }
9112        return result;
9113    }
9114
9115    private static byte[] concatHex(byte[] array1, byte[] array2) {
9116
9117        int len = array1.length + array2.length;
9118
9119        byte[] result = new byte[len];
9120
9121        int index = 0;
9122        if (array1.length != 0) {
9123            for (byte b : array1) {
9124                result[index] = b;
9125                index++;
9126            }
9127        }
9128
9129        if (array2.length != 0) {
9130            for (byte b : array2) {
9131                result[index] = b;
9132                index++;
9133            }
9134        }
9135
9136        return result;
9137    }
9138
9139    String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
9140        StringBuilder sb = new StringBuilder();
9141        for (String challenge : requestData) {
9142            if (challenge == null || challenge.isEmpty()) {
9143                continue;
9144            }
9145            logd("RAND = " + challenge);
9146
9147            byte[] rand = null;
9148            try {
9149                rand = parseHex(challenge);
9150            } catch (NumberFormatException e) {
9151                loge("malformed challenge");
9152                continue;
9153            }
9154
9155            String base64Challenge = android.util.Base64.encodeToString(
9156                    rand, android.util.Base64.NO_WRAP);
9157            /*
9158             * First, try with appType = 2 => USIM according to
9159             * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
9160             */
9161            int appType = 2;
9162            String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9163            if (tmResponse == null) {
9164                /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
9165                 * appType = 1 => SIM
9166                 */
9167                appType = 1;
9168                tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9169            }
9170            logv("Raw Response - " + tmResponse);
9171
9172            if (tmResponse == null || tmResponse.length() <= 4) {
9173                loge("bad response - " + tmResponse);
9174                return null;
9175            }
9176
9177            byte[] result = android.util.Base64.decode(tmResponse, android.util.Base64.DEFAULT);
9178            logv("Hex Response -" + makeHex(result));
9179            int sres_len = result[0];
9180            if (sres_len >= result.length) {
9181                loge("malfomed response - " + tmResponse);
9182                return null;
9183            }
9184            String sres = makeHex(result, 1, sres_len);
9185            int kc_offset = 1 + sres_len;
9186            if (kc_offset >= result.length) {
9187                loge("malfomed response - " + tmResponse);
9188                return null;
9189            }
9190            int kc_len = result[kc_offset];
9191            if (kc_offset + kc_len > result.length) {
9192                loge("malfomed response - " + tmResponse);
9193                return null;
9194            }
9195            String kc = makeHex(result, 1 + kc_offset, kc_len);
9196            sb.append(":" + kc + ":" + sres);
9197            logv("kc:" + kc + " sres:" + sres);
9198        }
9199
9200        return sb.toString();
9201    }
9202
9203    void handleGsmAuthRequest(SimAuthRequestData requestData) {
9204        if (targetWificonfiguration == null
9205                || targetWificonfiguration.networkId == requestData.networkId) {
9206            logd("id matches targetWifiConfiguration");
9207        } else {
9208            logd("id does not match targetWifiConfiguration");
9209            return;
9210        }
9211
9212        TelephonyManager tm = (TelephonyManager)
9213                mContext.getSystemService(Context.TELEPHONY_SERVICE);
9214
9215        if (tm == null) {
9216            loge("could not get telephony manager");
9217            mWifiNative.simAuthFailedResponse(requestData.networkId);
9218            return;
9219        }
9220
9221        String response = getGsmSimAuthResponse(requestData.data, tm);
9222        if (response == null) {
9223            mWifiNative.simAuthFailedResponse(requestData.networkId);
9224        } else {
9225            logv("Supplicant Response -" + response);
9226            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
9227        }
9228    }
9229
9230    void handle3GAuthRequest(SimAuthRequestData requestData) {
9231        StringBuilder sb = new StringBuilder();
9232        byte[] rand = null;
9233        byte[] authn = null;
9234        String res_type = "UMTS-AUTH";
9235
9236        if (targetWificonfiguration == null
9237                || targetWificonfiguration.networkId == requestData.networkId) {
9238            logd("id matches targetWifiConfiguration");
9239        } else {
9240            logd("id does not match targetWifiConfiguration");
9241            return;
9242        }
9243        if (requestData.data.length == 2) {
9244            try {
9245                rand = parseHex(requestData.data[0]);
9246                authn = parseHex(requestData.data[1]);
9247            } catch (NumberFormatException e) {
9248                loge("malformed challenge");
9249            }
9250        } else {
9251               loge("malformed challenge");
9252        }
9253
9254        String tmResponse = "";
9255        if (rand != null && authn != null) {
9256            String base64Challenge = android.util.Base64.encodeToString(
9257                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
9258
9259            TelephonyManager tm = (TelephonyManager)
9260                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
9261            if (tm != null) {
9262                int appType = 2; // 2 => USIM
9263                tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9264                logv("Raw Response - " + tmResponse);
9265            } else {
9266                loge("could not get telephony manager");
9267            }
9268        }
9269
9270        boolean good_response = false;
9271        if (tmResponse != null && tmResponse.length() > 4) {
9272            byte[] result = android.util.Base64.decode(tmResponse,
9273                    android.util.Base64.DEFAULT);
9274            loge("Hex Response - " + makeHex(result));
9275            byte tag = result[0];
9276            if (tag == (byte) 0xdb) {
9277                logv("successful 3G authentication ");
9278                int res_len = result[1];
9279                String res = makeHex(result, 2, res_len);
9280                int ck_len = result[res_len + 2];
9281                String ck = makeHex(result, res_len + 3, ck_len);
9282                int ik_len = result[res_len + ck_len + 3];
9283                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
9284                sb.append(":" + ik + ":" + ck + ":" + res);
9285                logv("ik:" + ik + "ck:" + ck + " res:" + res);
9286                good_response = true;
9287            } else if (tag == (byte) 0xdc) {
9288                loge("synchronisation failure");
9289                int auts_len = result[1];
9290                String auts = makeHex(result, 2, auts_len);
9291                res_type = "UMTS-AUTS";
9292                sb.append(":" + auts);
9293                logv("auts:" + auts);
9294                good_response = true;
9295            } else {
9296                loge("bad response - unknown tag = " + tag);
9297            }
9298        } else {
9299            loge("bad response - " + tmResponse);
9300        }
9301
9302        if (good_response) {
9303            String response = sb.toString();
9304            logv("Supplicant Response -" + response);
9305            mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
9306        } else {
9307            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
9308        }
9309    }
9310
9311    public int getCurrentUserId() {
9312        return mCurrentUserId;
9313    }
9314
9315    private boolean isCurrentUserProfile(int userId) {
9316        if (userId == mCurrentUserId) {
9317            return true;
9318        }
9319        final UserInfo parent = mUserManager.getProfileParent(userId);
9320        return parent != null && parent.id == mCurrentUserId;
9321    }
9322
9323    public List<UserInfo> getCurrentUserProfiles() {
9324        return mUserManager.getProfiles(mCurrentUserId);
9325    }
9326
9327    /**
9328     * @param reason reason code from supplicant on network disconnected event
9329     * @return true if this is a suspicious disconnect
9330     */
9331    static boolean unexpectedDisconnectedReason(int reason) {
9332        return reason == 2              // PREV_AUTH_NOT_VALID
9333                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
9334                || reason == 7          // FRAME_FROM_NONASSOC_STA
9335                || reason == 8          // STA_HAS_LEFT
9336                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
9337                || reason == 14         // MICHAEL_MIC_FAILURE
9338                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
9339                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
9340                || reason == 18         // GROUP_CIPHER_NOT_VALID
9341                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
9342                || reason == 23         // IEEE_802_1X_AUTH_FAILED
9343                || reason == 34;        // DISASSOC_LOW_ACK
9344    }
9345
9346    /**
9347     * Update WifiMetrics before dumping
9348     */
9349    void updateWifiMetrics() {
9350        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworksSize();
9351        int numOpenNetworks = 0;
9352        int numPersonalNetworks = 0;
9353        int numEnterpriseNetworks = 0;
9354        int numNetworksAddedByUser = 0;
9355        int numNetworksAddedByApps = 0;
9356        for (WifiConfiguration config : mWifiConfigManager.getConfiguredNetworks()) {
9357            if (config.allowedAuthAlgorithms.get(WifiConfiguration.AuthAlgorithm.OPEN)) {
9358                numOpenNetworks++;
9359            } else if (config.isEnterprise()) {
9360                numEnterpriseNetworks++;
9361            } else {
9362                numPersonalNetworks++;
9363            }
9364            if (config.selfAdded) {
9365                numNetworksAddedByUser++;
9366            } else {
9367                numNetworksAddedByApps++;
9368            }
9369        }
9370        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
9371        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
9372        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
9373        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
9374        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
9375        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
9376
9377        /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually
9378        mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt(
9379                mContext.getContentResolver(),
9380                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
9381                != Settings.Secure.LOCATION_MODE_OFF);
9382                */
9383
9384        /* <TODO> decide how statemachine will access WifiSettingsStore
9385        mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable());
9386         */
9387    }
9388
9389    private static String getLinkPropertiesSummary(LinkProperties lp) {
9390        List<String> attributes = new ArrayList(6);
9391        if (lp.hasIPv4Address()) {
9392            attributes.add("v4");
9393        }
9394        if (lp.hasIPv4DefaultRoute()) {
9395            attributes.add("v4r");
9396        }
9397        if (lp.hasIPv4DnsServer()) {
9398            attributes.add("v4dns");
9399        }
9400        if (lp.hasGlobalIPv6Address()) {
9401            attributes.add("v6");
9402        }
9403        if (lp.hasIPv6DefaultRoute()) {
9404            attributes.add("v6r");
9405        }
9406        if (lp.hasIPv6DnsServer()) {
9407            attributes.add("v6dns");
9408        }
9409
9410        // TODO: Replace with String.join(" ", attributes) once we're fully on JDK 8.
9411        StringBuilder sb = new StringBuilder();
9412        boolean first = true;
9413        for (String attr : attributes) {
9414            if (!first) {
9415                sb.append(" ");
9416            } else {
9417                first = false;
9418            }
9419            sb.append(attr);
9420        }
9421        return sb.toString();
9422    }
9423
9424    /**
9425     * Try to connect to the network of candidate. According to the current connected network, this
9426     * API determines whether no action, disconnect and connect, or roaming.
9427     *
9428     * @param candidate the candidate network to connect to
9429     */
9430    private void tryToConnectToNetwork(WifiConfiguration candidate) {
9431        if (candidate == null) {
9432            if (DBG) {
9433                Log.d(TAG, "Try to connect to null, give up");
9434            }
9435            return;
9436        }
9437
9438        ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
9439        if (scanResultCandidate == null) {
9440            Log.e(TAG, "tryToConnectToNetwork: bad candidate. Network:"  + candidate
9441                    + " scanresult: " + scanResultCandidate);
9442            return;
9443        }
9444
9445        String targetBssid = scanResultCandidate.BSSID;
9446        String  targetAssociationId = candidate.SSID + " : " + targetBssid;
9447        if (targetBssid != null && targetBssid.equals(mWifiInfo.getBSSID())) {
9448            if (DBG) {
9449                Log.d(TAG, "tryToConnectToNetwork: Already connect to" + targetAssociationId);
9450            }
9451            return;
9452        }
9453
9454        WifiConfiguration currentConnectedNetwork = mWifiConfigManager
9455                .getWifiConfiguration(mWifiInfo.getNetworkId());
9456        String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :
9457                (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());
9458
9459        if (currentConnectedNetwork != null
9460                && (currentConnectedNetwork.networkId == candidate.networkId
9461                || currentConnectedNetwork.isLinked(candidate))) {
9462            if (DBG) {
9463                Log.d(TAG, "tryToConnectToNetwork: Roaming from " + currentAssociationId + " to "
9464                        + targetAssociationId);
9465            }
9466            sendMessage(CMD_AUTO_ROAM, candidate.networkId, 0, scanResultCandidate);
9467        } else {
9468            if (DBG) {
9469                Log.d(TAG, "tryToConnectToNetwork: Reconnect from " + currentAssociationId + " to "
9470                        + targetAssociationId);
9471            }
9472
9473            sendMessage(CMD_AUTO_CONNECT, candidate.networkId, 0, scanResultCandidate.BSSID);
9474        }
9475    }
9476}
9477