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