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