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