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