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