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