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