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