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