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