WifiStateMachine.java revision da94688198c864bb29be2e9603ebbe9ae6492a87
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.PendingIntent;
33import android.bluetooth.BluetoothAdapter;
34import android.content.BroadcastReceiver;
35import android.content.Context;
36import android.content.Intent;
37import android.content.IntentFilter;
38import android.content.pm.ApplicationInfo;
39import android.content.pm.IPackageManager;
40import android.content.pm.PackageManager;
41import android.database.ContentObserver;
42import android.net.ConnectivityManager;
43import android.net.DhcpResults;
44import android.net.IpConfiguration;
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.IApInterface;
60import android.net.wifi.IClientInterface;
61import android.net.wifi.IWificond;
62import android.net.wifi.PasspointManagementObjectDefinition;
63import android.net.wifi.RssiPacketCountInfo;
64import android.net.wifi.ScanResult;
65import android.net.wifi.ScanSettings;
66import android.net.wifi.SupplicantState;
67import android.net.wifi.WifiChannel;
68import android.net.wifi.WifiConfiguration;
69import android.net.wifi.WifiConnectionStatistics;
70import android.net.wifi.WifiEnterpriseConfig;
71import android.net.wifi.WifiInfo;
72import android.net.wifi.WifiLinkLayerStats;
73import android.net.wifi.WifiManager;
74import android.net.wifi.WifiScanner;
75import android.net.wifi.WifiSsid;
76import android.net.wifi.WpsInfo;
77import android.net.wifi.WpsResult;
78import android.net.wifi.WpsResult.Status;
79import android.net.wifi.aware.WifiAwareManager;
80import android.net.wifi.p2p.IWifiP2pManager;
81import android.os.BatteryStats;
82import android.os.Binder;
83import android.os.Bundle;
84import android.os.IBinder;
85import android.os.INetworkManagementService;
86import android.os.Looper;
87import android.os.Message;
88import android.os.Messenger;
89import android.os.PowerManager;
90import android.os.Process;
91import android.os.RemoteException;
92import android.os.UserHandle;
93import android.os.UserManager;
94import android.os.WorkSource;
95import android.provider.Settings;
96import android.telephony.TelephonyManager;
97import android.text.TextUtils;
98import android.util.Log;
99import android.util.SparseArray;
100
101import com.android.internal.R;
102import com.android.internal.annotations.GuardedBy;
103import com.android.internal.annotations.VisibleForTesting;
104import com.android.internal.app.IBatteryStats;
105import com.android.internal.util.AsyncChannel;
106import com.android.internal.util.MessageUtils;
107import com.android.internal.util.Protocol;
108import com.android.internal.util.State;
109import com.android.internal.util.StateMachine;
110import com.android.server.connectivity.KeepalivePacketData;
111import com.android.server.wifi.hotspot2.IconEvent;
112import com.android.server.wifi.hotspot2.PasspointManager;
113import com.android.server.wifi.hotspot2.Utils;
114import com.android.server.wifi.hotspot2.WnmData;
115import com.android.server.wifi.nano.WifiMetricsProto;
116import com.android.server.wifi.p2p.WifiP2pServiceImpl;
117import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
118import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
119import com.android.server.wifi.util.TelephonyUtil;
120
121import java.io.BufferedReader;
122import java.io.FileDescriptor;
123import java.io.FileNotFoundException;
124import java.io.FileReader;
125import java.io.IOException;
126import java.io.PrintWriter;
127import java.net.Inet4Address;
128import java.net.InetAddress;
129import java.util.ArrayList;
130import java.util.Arrays;
131import java.util.HashSet;
132import java.util.LinkedList;
133import java.util.List;
134import java.util.Queue;
135import java.util.Set;
136import java.util.concurrent.atomic.AtomicBoolean;
137import java.util.concurrent.atomic.AtomicInteger;
138
139/**
140 * TODO:
141 * Deprecate WIFI_STATE_UNKNOWN
142 */
143
144/**
145 * Track the state of Wifi connectivity. All event handling is done here,
146 * and all changes in connectivity state are initiated here.
147 *
148 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
149 * In the current implementation, we support concurrent wifi p2p and wifi operation.
150 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
151 * handles p2p operation.
152 *
153 * @hide
154 */
155public class WifiStateMachine extends StateMachine implements WifiNative.WifiRssiEventHandler,
156        WifiMulticastLockManager.FilterController {
157
158    private static final String NETWORKTYPE = "WIFI";
159    private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT";
160    @VisibleForTesting public static final short NUM_LOG_RECS_NORMAL = 100;
161    @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE_LOW_MEMORY = 200;
162    @VisibleForTesting public static final short NUM_LOG_RECS_VERBOSE = 3000;
163    private static final String TAG = "WifiStateMachine";
164
165    private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
166
167    private static final String GOOGLE_OUI = "DA-A1-19";
168
169    private static final String EXTRA_OSU_ICON_QUERY_BSSID = "BSSID";
170    private static final String EXTRA_OSU_ICON_QUERY_FILENAME = "FILENAME";
171
172    private boolean mVerboseLoggingEnabled = false;
173
174    /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
175     * the corresponding BSSID.
176     */
177    private boolean didBlackListBSSID = false;
178
179    /**
180     * Log with error attribute
181     *
182     * @param s is string log
183     */
184    @Override
185    protected void loge(String s) {
186        Log.e(getName(), s);
187    }
188    @Override
189    protected void logd(String s) {
190        Log.d(getName(), s);
191    }
192    @Override
193    protected void log(String s) {
194        Log.d(getName(), s);
195    }
196    private WifiMetrics mWifiMetrics;
197    private WifiInjector mWifiInjector;
198    private WifiMonitor mWifiMonitor;
199    private WifiNative mWifiNative;
200    private WifiConfigManager mWifiConfigManager;
201    private WifiSupplicantControl mWifiSupplicantControl;
202    private WifiConnectivityManager mWifiConnectivityManager;
203    private WifiNetworkSelector mWifiNetworkSelector;
204    private INetworkManagementService mNwService;
205    private IWificond mWificond;
206    private IClientInterface mClientInterface;
207    private ConnectivityManager mCm;
208    private BaseWifiDiagnostics mWifiDiagnostics;
209    private WifiApConfigStore mWifiApConfigStore;
210    private final boolean mP2pSupported;
211    private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
212    private final boolean mAwareSupported;
213    private boolean mTemporarilyDisconnectWifi = false;
214    private final String mPrimaryDeviceType;
215    private final Clock mClock;
216    private final PropertyService mPropertyService;
217    private final BuildProperties mBuildProperties;
218    private final WifiCountryCode mCountryCode;
219    // Object holding most recent wifi score report and bad Linkspeed count
220    private final WifiScoreReport mWifiScoreReport;
221    private final PasspointManager mPasspointManager;
222
223    /* Scan results handling */
224    private List<ScanDetail> mScanResults = new ArrayList<>();
225    private final Object mScanResultsLock = new Object();
226
227    // For debug, number of known scan results that were found as part of last scan result event,
228    // as well the number of scans results returned by the supplicant with that message
229    private int mNumScanResultsKnown;
230    private int mNumScanResultsReturned;
231
232    private boolean mScreenOn = false;
233
234    private final String mInterfaceName;
235
236    private int mLastSignalLevel = -1;
237    private String mLastBssid;
238    private int mLastNetworkId; // The network Id we successfully joined
239    private boolean mIsLinkDebouncing = false;
240    private final StateMachineDeathRecipient mDeathRecipient =
241            new StateMachineDeathRecipient(this, CMD_CLIENT_INTERFACE_BINDER_DEATH);
242    private boolean mIpReachabilityDisconnectEnabled = true;
243
244    @Override
245    public void onRssiThresholdBreached(byte curRssi) {
246        if (mVerboseLoggingEnabled) {
247            Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi);
248        }
249        sendMessage(CMD_RSSI_THRESHOLD_BREACH, curRssi);
250    }
251
252    public void processRssiThreshold(byte curRssi, int reason) {
253        if (curRssi == Byte.MAX_VALUE || curRssi == Byte.MIN_VALUE) {
254            Log.wtf(TAG, "processRssiThreshold: Invalid rssi " + curRssi);
255            return;
256        }
257        for (int i = 0; i < mRssiRanges.length; i++) {
258            if (curRssi < mRssiRanges[i]) {
259                // Assume sorted values(ascending order) for rssi,
260                // bounded by high(127) and low(-128) at extremeties
261                byte maxRssi = mRssiRanges[i];
262                byte minRssi = mRssiRanges[i-1];
263                // This value of hw has to be believed as this value is averaged and has breached
264                // the rssi thresholds and raised event to host. This would be eggregious if this
265                // value is invalid
266                mWifiInfo.setRssi(curRssi);
267                updateCapabilities(getCurrentWifiConfiguration());
268                int ret = startRssiMonitoringOffload(maxRssi, minRssi);
269                Log.d(TAG, "Re-program RSSI thresholds for " + smToString(reason) +
270                        ": [" + minRssi + ", " + maxRssi + "], curRssi=" + curRssi + " ret=" + ret);
271                break;
272            }
273        }
274    }
275
276    // Testing various network disconnect cases by sending lots of spurious
277    // disconnect to supplicant
278    private boolean testNetworkDisconnect = false;
279
280    private boolean mEnableRssiPolling = false;
281    private int mRssiPollToken = 0;
282    /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
283    * In CONNECT_MODE, the STA can scan and connect to an access point
284    * In SCAN_ONLY_MODE, the STA can only scan for access points
285    * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
286    */
287    private int mOperationalMode = CONNECT_MODE;
288    private boolean mIsScanOngoing = false;
289    private boolean mIsFullScanOngoing = false;
290
291    private final Queue<Message> mBufferedScanMsg = new LinkedList<>();
292    private static final int UNKNOWN_SCAN_SOURCE = -1;
293    private static final int ADD_OR_UPDATE_SOURCE = -3;
294
295    private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
296    private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
297    private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
298    private static final String SCAN_REQUEST_TIME = "scan_request_time";
299
300    private boolean mBluetoothConnectionActive = false;
301
302    private PowerManager.WakeLock mSuspendWakeLock;
303
304    /**
305     * Interval in milliseconds between polling for RSSI
306     * and linkspeed information
307     */
308    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
309
310    /**
311     * Interval in milliseconds between receiving a disconnect event
312     * while connected to a good AP, and handling the disconnect proper
313     */
314    private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 4000;
315
316    /**
317     * Delay between supplicant restarts upon failure to establish connection
318     */
319    private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
320
321    /**
322     * Number of times we attempt to restart supplicant
323     */
324    private static final int SUPPLICANT_RESTART_TRIES = 5;
325
326    /**
327     * Value to set in wpa_supplicant "bssid" field when we don't want to restrict connection to
328     * a specific AP.
329     */
330    private static final String SUPPLICANT_BSSID_ANY = "any";
331
332    private int mSupplicantRestartCount = 0;
333    /* Tracks sequence number on stop failure message */
334    private int mSupplicantStopFailureToken = 0;
335
336    /**
337     * The link properties of the wifi interface.
338     * Do not modify this directly; use updateLinkProperties instead.
339     */
340    private LinkProperties mLinkProperties;
341
342    /* Tracks sequence number on a periodic scan message */
343    private int mPeriodicScanToken = 0;
344
345    // Wakelock held during wifi start/stop and driver load/unload
346    private PowerManager.WakeLock mWakeLock;
347
348    private Context mContext;
349
350    private final Object mDhcpResultsLock = new Object();
351    private DhcpResults mDhcpResults;
352
353    // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
354    private final WifiInfo mWifiInfo;
355    private NetworkInfo mNetworkInfo;
356    private final NetworkCapabilities mDfltNetworkCapabilities;
357    private SupplicantStateTracker mSupplicantStateTracker;
358
359    private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
360
361    // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress
362    private boolean mAutoRoaming = false;
363
364    // Roaming failure count
365    private int mRoamFailCount = 0;
366
367    // This is the BSSID we are trying to associate to, it can be set to SUPPLICANT_BSSID_ANY
368    // if we havent selected a BSSID for joining.
369    private String mTargetRoamBSSID = SUPPLICANT_BSSID_ANY;
370    // This one is used to track whta is the current target network ID. This is used for error
371    // handling during connection setup since many error message from supplicant does not report
372    // SSID Once connected, it will be set to invalid
373    private int mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
374    private long mLastDriverRoamAttempt = 0;
375    private WifiConfiguration targetWificonfiguration = null;
376
377    boolean isRoaming() {
378        return mAutoRoaming;
379    }
380
381    /**
382     * Method to clear {@link #mTargetRoamBSSID} and reset the the current connected network's
383     * bssid in wpa_supplicant after a roam/connect attempt.
384     */
385    public boolean clearTargetBssid(String dbg) {
386        WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
387        if (config == null) {
388            return false;
389        }
390        String bssid = SUPPLICANT_BSSID_ANY;
391        if (config.BSSID != null) {
392            bssid = config.BSSID;
393            if (mVerboseLoggingEnabled) {
394                Log.d(TAG, "force BSSID to " + bssid + "due to config");
395            }
396        }
397        if (mVerboseLoggingEnabled) {
398            logd(dbg + " clearTargetBssid " + bssid + " key=" + config.configKey());
399        }
400        mTargetRoamBSSID = bssid;
401        return mWifiSupplicantControl.setConfiguredNetworkBSSID(bssid);
402    }
403
404    /**
405     * Set Config's default BSSID (for association purpose) and {@link #mTargetRoamBSSID}
406     * @param config config need set BSSID
407     * @param bssid  default BSSID to assocaite with when connect to this network
408     * @return false -- does not change the current default BSSID of the configure
409     *         true -- change the  current default BSSID of the configur
410     */
411    private boolean setTargetBssid(WifiConfiguration config, String bssid) {
412        if (config == null || bssid == null) {
413            return false;
414        }
415        if (config.BSSID != null) {
416            bssid = config.BSSID;
417            if (mVerboseLoggingEnabled) {
418                Log.d(TAG, "force BSSID to " + bssid + "due to config");
419            }
420        }
421        if (mVerboseLoggingEnabled) {
422            Log.d(TAG, "setTargetBssid set to " + bssid + " key=" + config.configKey());
423        }
424        mTargetRoamBSSID = bssid;
425        config.getNetworkSelectionStatus().setNetworkSelectionBSSID(bssid);
426        return true;
427    }
428
429    private final IpManager mIpManager;
430
431    // Channel for sending replies.
432    private AsyncChannel mReplyChannel = new AsyncChannel();
433
434    private WifiP2pServiceImpl mWifiP2pServiceImpl;
435    private WifiAwareManager mWifiAwareManager;
436
437    // Used to initiate a connection with WifiP2pService
438    private AsyncChannel mWifiP2pChannel;
439
440    private WifiScanner mWifiScanner;
441
442    @GuardedBy("mWifiReqCountLock")
443    private int mConnectionReqCount = 0;
444    private WifiNetworkFactory mNetworkFactory;
445    @GuardedBy("mWifiReqCountLock")
446    private int mUntrustedReqCount = 0;
447    private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
448    private WifiNetworkAgent mNetworkAgent;
449    private final Object mWifiReqCountLock = new Object();
450
451    private byte[] mRssiRanges;
452
453    // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
454    // We should really persist that into the networkHistory.txt file, and read it back when
455    // WifiStateMachine starts up
456    private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics();
457
458    // Used to filter out requests we couldn't possibly satisfy.
459    private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
460
461    // Provide packet filter capabilities to ConnectivityService.
462    private final NetworkMisc mNetworkMisc = new NetworkMisc();
463
464    /* The base for wifi message types */
465    static final int BASE = Protocol.BASE_WIFI;
466    /* Start the supplicant */
467    static final int CMD_START_SUPPLICANT                               = BASE + 11;
468    /* Stop the supplicant */
469    static final int CMD_STOP_SUPPLICANT                                = BASE + 12;
470    /* Indicates Static IP succeeded */
471    static final int CMD_STATIC_IP_SUCCESS                              = BASE + 15;
472    /* Indicates Static IP failed */
473    static final int CMD_STATIC_IP_FAILURE                              = BASE + 16;
474    /* Indicates supplicant stop failed */
475    static final int CMD_STOP_SUPPLICANT_FAILED                         = BASE + 17;
476    /* A delayed message sent to start driver when it fail to come up */
477    static final int CMD_DRIVER_START_TIMED_OUT                         = BASE + 19;
478
479    /* Start the soft access point */
480    static final int CMD_START_AP                                       = BASE + 21;
481    /* Indicates soft ap start failed */
482    static final int CMD_START_AP_FAILURE                               = BASE + 22;
483    /* Stop the soft access point */
484    static final int CMD_STOP_AP                                        = BASE + 23;
485    /* Soft access point teardown is completed. */
486    static final int CMD_AP_STOPPED                                     = BASE + 24;
487
488    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE                 = BASE + 31;
489
490    /* Supplicant commands */
491    /* Is supplicant alive ? */
492    static final int CMD_PING_SUPPLICANT                                = BASE + 51;
493    /* Add/update a network configuration */
494    static final int CMD_ADD_OR_UPDATE_NETWORK                          = BASE + 52;
495    /* Delete a network */
496    static final int CMD_REMOVE_NETWORK                                 = BASE + 53;
497    /* Enable a network. The device will attempt a connection to the given network. */
498    static final int CMD_ENABLE_NETWORK                                 = BASE + 54;
499    /* Save configuration */
500    static final int CMD_SAVE_CONFIG                                    = BASE + 58;
501    /* Get configured networks */
502    static final int CMD_GET_CONFIGURED_NETWORKS                        = BASE + 59;
503    /* Get adaptors */
504    static final int CMD_GET_SUPPORTED_FEATURES                         = BASE + 61;
505    /* Get configured networks with real preSharedKey */
506    static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS             = BASE + 62;
507    /* Get Link Layer Stats thru HAL */
508    static final int CMD_GET_LINK_LAYER_STATS                           = BASE + 63;
509    /* Supplicant commands after driver start*/
510    /* Initiate a scan */
511    static final int CMD_START_SCAN                                     = BASE + 71;
512    /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
513    static final int CMD_SET_OPERATIONAL_MODE                           = BASE + 72;
514    /* Disconnect from a network */
515    static final int CMD_DISCONNECT                                     = BASE + 73;
516    /* Reconnect to a network */
517    static final int CMD_RECONNECT                                      = BASE + 74;
518    /* Reassociate to a network */
519    static final int CMD_REASSOCIATE                                    = BASE + 75;
520    /* Get Connection Statistis */
521    static final int CMD_GET_CONNECTION_STATISTICS                      = BASE + 76;
522
523    /* Controls suspend mode optimizations
524     *
525     * When high perf mode is enabled, suspend mode optimizations are disabled
526     *
527     * When high perf mode is disabled, suspend mode optimizations are enabled
528     *
529     * Suspend mode optimizations include:
530     * - packet filtering
531     * - turn off roaming
532     * - DTIM wake up settings
533     */
534    static final int CMD_SET_HIGH_PERF_MODE                             = BASE + 77;
535    /* Enables RSSI poll */
536    static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
537    /* RSSI poll */
538    static final int CMD_RSSI_POLL                                      = BASE + 83;
539    /* Enable suspend mode optimizations in the driver */
540    static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
541    /* Delayed NETWORK_DISCONNECT */
542    static final int CMD_DELAYED_NETWORK_DISCONNECT                     = BASE + 87;
543    /* When there are no saved networks, we do a periodic scan to notify user of
544     * an open network */
545    static final int CMD_NO_NETWORKS_PERIODIC_SCAN                      = BASE + 88;
546    /* Test network Disconnection NETWORK_DISCONNECT */
547    static final int CMD_TEST_NETWORK_DISCONNECT                        = BASE + 89;
548
549    private int testNetworkDisconnectCounter = 0;
550
551    /* Enable TDLS on a specific MAC address */
552    static final int CMD_ENABLE_TDLS                                    = BASE + 92;
553
554    /**
555     * Watchdog for protecting against b/16823537
556     * Leave time for 4-way handshake to succeed
557     */
558    static final int ROAM_GUARD_TIMER_MSEC = 15000;
559
560    int roamWatchdogCount = 0;
561    /* Roam state watchdog */
562    static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
563    /* Screen change intent handling */
564    static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
565
566    /* Disconnecting state watchdog */
567    static final int CMD_DISCONNECTING_WATCHDOG_TIMER                   = BASE + 96;
568
569    /* Remove a packages associated configrations */
570    static final int CMD_REMOVE_APP_CONFIGURATIONS                      = BASE + 97;
571
572    /* Disable an ephemeral network */
573    static final int CMD_DISABLE_EPHEMERAL_NETWORK                      = BASE + 98;
574
575    /* Get matching network */
576    static final int CMD_GET_MATCHING_CONFIG                            = BASE + 99;
577
578    /* alert from firmware */
579    static final int CMD_FIRMWARE_ALERT                                 = BASE + 100;
580
581    /* SIM is removed; reset any cached data for it */
582    static final int CMD_RESET_SIM_NETWORKS                             = BASE + 101;
583
584    /* OSU APIs */
585    static final int CMD_ADD_PASSPOINT_MO                               = BASE + 102;
586    static final int CMD_MODIFY_PASSPOINT_MO                            = BASE + 103;
587    static final int CMD_QUERY_OSU_ICON                                 = BASE + 104;
588
589    /* try to match a provider with current network */
590    static final int CMD_MATCH_PROVIDER_NETWORK                         = BASE + 105;
591
592    /* Commands from/to the SupplicantStateTracker */
593    /* Reset the supplicant state tracker */
594    static final int CMD_RESET_SUPPLICANT_STATE                         = BASE + 111;
595
596    int disconnectingWatchdogCount = 0;
597    static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
598
599    /* P2p commands */
600    /* We are ok with no response here since we wont do much with it anyway */
601    public static final int CMD_ENABLE_P2P                              = BASE + 131;
602    /* In order to shut down supplicant cleanly, we wait till p2p has
603     * been disabled */
604    public static final int CMD_DISABLE_P2P_REQ                         = BASE + 132;
605    public static final int CMD_DISABLE_P2P_RSP                         = BASE + 133;
606
607    public static final int CMD_BOOT_COMPLETED                          = BASE + 134;
608
609    /* We now have a valid IP configuration. */
610    static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
611    /* We no longer have a valid IP configuration. */
612    static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
613    /* Link configuration (IP address, DNS, ...) changes notified via netlink */
614    static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
615
616    /* Supplicant is trying to associate to a given BSSID */
617    static final int CMD_TARGET_BSSID                                   = BASE + 141;
618
619    /* Reload all networks and reconnect */
620    static final int CMD_RELOAD_TLS_AND_RECONNECT                       = BASE + 142;
621
622    static final int CMD_START_CONNECT                                  = BASE + 143;
623
624    private static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
625    private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
626    private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
627
628    static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
629
630    static final int CMD_START_ROAM                                     = BASE + 145;
631
632    static final int CMD_ASSOCIATED_BSSID                               = BASE + 147;
633
634    static final int CMD_NETWORK_STATUS                                 = BASE + 148;
635
636    /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
637    static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
638
639    /* Remove a packages associated configrations */
640    static final int CMD_REMOVE_USER_CONFIGURATIONS                     = BASE + 152;
641
642    static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
643
644    /* used to offload sending IP packet */
645    static final int CMD_START_IP_PACKET_OFFLOAD                        = BASE + 160;
646
647    /* used to stop offload sending IP packet */
648    static final int CMD_STOP_IP_PACKET_OFFLOAD                         = BASE + 161;
649
650    /* used to start rssi monitoring in hw */
651    static final int CMD_START_RSSI_MONITORING_OFFLOAD                  = BASE + 162;
652
653    /* used to stop rssi moniroting in hw */
654    static final int CMD_STOP_RSSI_MONITORING_OFFLOAD                   = BASE + 163;
655
656    /* used to indicated RSSI threshold breach in hw */
657    static final int CMD_RSSI_THRESHOLD_BREACH                          = BASE + 164;
658
659    /* Enable/Disable WifiConnectivityManager */
660    static final int CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER               = BASE + 166;
661
662    /* Enable/Disable AutoJoin when associated */
663    static final int CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED                = BASE + 167;
664
665    /**
666     * Used to handle messages bounced between WifiStateMachine and IpManager.
667     */
668    static final int CMD_IPV4_PROVISIONING_SUCCESS                      = BASE + 200;
669    static final int CMD_IPV4_PROVISIONING_FAILURE                      = BASE + 201;
670
671    /* Push a new APF program to the HAL */
672    static final int CMD_INSTALL_PACKET_FILTER                          = BASE + 202;
673
674    /* Enable/disable fallback packet filtering */
675    static final int CMD_SET_FALLBACK_PACKET_FILTERING                  = BASE + 203;
676
677    /* Enable/disable Neighbor Discovery offload functionality. */
678    static final int CMD_CONFIG_ND_OFFLOAD                              = BASE + 204;
679
680    /* used to indicate that the foreground user was switched */
681    static final int CMD_USER_SWITCH                                    = BASE + 205;
682
683    /* used to indicate that the foreground user was switched */
684    static final int CMD_USER_UNLOCK                                    = BASE + 206;
685
686    /* used to indicate that the foreground user was switched */
687    static final int CMD_USER_STOP                                      = BASE + 207;
688
689    /**
690     * Signals that IClientInterface instance underpinning our state is dead.
691     */
692    private static final int CMD_CLIENT_INTERFACE_BINDER_DEATH = BASE + 250;
693
694    // For message logging.
695    private static final Class[] sMessageClasses = {
696            AsyncChannel.class, WifiStateMachine.class, DhcpClient.class };
697    private static final SparseArray<String> sSmToString =
698            MessageUtils.findMessageNames(sMessageClasses);
699
700
701    /* Wifi state machine modes of operation */
702    /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
703    public static final int CONNECT_MODE = 1;
704    /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
705    public static final int SCAN_ONLY_MODE = 2;
706    /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
707    public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
708    /* DISABLED_MODE - Don't connect, don't scan, don't be an AP */
709    public static final int DISABLED_MODE = 4;
710
711    private static final int SUCCESS = 1;
712    private static final int FAILURE = -1;
713
714    /* Tracks if suspend optimizations need to be disabled by DHCP,
715     * screen or due to high perf mode.
716     * When any of them needs to disable it, we keep the suspend optimizations
717     * disabled
718     */
719    private int mSuspendOptNeedsDisabled = 0;
720
721    private static final int SUSPEND_DUE_TO_DHCP = 1;
722    private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
723    private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
724
725    /* Tracks if user has enabled suspend optimizations through settings */
726    private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
727
728    /**
729     * Scan period for the NO_NETWORKS_PERIIDOC_SCAN_FEATURE
730     */
731    private final int mNoNetworksPeriodicScan;
732
733    /**
734     * Supplicant scan interval in milliseconds.
735     * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
736     * from the default config if the setting is not set
737     */
738    private long mSupplicantScanIntervalMs;
739
740    private boolean mEnableAutoJoinWhenAssociated;
741    private int mAlwaysEnableScansWhileAssociated;
742    private final int mThresholdQualifiedRssi24;
743    private final int mThresholdQualifiedRssi5;
744    private final int mThresholdSaturatedRssi24;
745    private final int mThresholdSaturatedRssi5;
746    private final int mThresholdMinimumRssi5;
747    private final int mThresholdMinimumRssi24;
748    private final boolean mEnableLinkDebouncing;
749    private final boolean mEnableChipWakeUpWhenAssociated;
750    private final boolean mEnableRssiPollWhenAssociated;
751
752    int mRunningBeaconCount = 0;
753
754    /* Default parent state */
755    private State mDefaultState = new DefaultState();
756    /* Temporary initial state */
757    private State mInitialState = new InitialState();
758    /* Driver loaded, waiting for supplicant to start */
759    private State mSupplicantStartingState = new SupplicantStartingState();
760    /* Driver loaded and supplicant ready */
761    private State mSupplicantStartedState = new SupplicantStartedState();
762    /* Waiting for supplicant to stop and monitor to exit */
763    private State mSupplicantStoppingState = new SupplicantStoppingState();
764    /* Wait until p2p is disabled
765     * This is a special state which is entered right after we exit out of DriverStartedState
766     * before transitioning to another state.
767     */
768    private State mWaitForP2pDisableState = new WaitForP2pDisableState();
769    /* Scan for networks, no connection will be established */
770    private State mScanModeState = new ScanModeState();
771    /* Connecting to an access point */
772    private State mConnectModeState = new ConnectModeState();
773    /* Connected at 802.11 (L2) level */
774    private State mL2ConnectedState = new L2ConnectedState();
775    /* fetching IP after connection to access point (assoc+auth complete) */
776    private State mObtainingIpState = new ObtainingIpState();
777    /* Connected with IP addr */
778    private State mConnectedState = new ConnectedState();
779    /* Roaming */
780    private State mRoamingState = new RoamingState();
781    /* disconnect issued, waiting for network disconnect confirmation */
782    private State mDisconnectingState = new DisconnectingState();
783    /* Network is not connected, supplicant assoc+auth is not complete */
784    private State mDisconnectedState = new DisconnectedState();
785    /* Waiting for WPS to be completed*/
786    private State mWpsRunningState = new WpsRunningState();
787    /* Soft ap state */
788    private State mSoftApState = new SoftApState();
789
790    /**
791     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
792     * {@link WifiManager#WIFI_STATE_DISABLING},
793     * {@link WifiManager#WIFI_STATE_ENABLED},
794     * {@link WifiManager#WIFI_STATE_ENABLING},
795     * {@link WifiManager#WIFI_STATE_UNKNOWN}
796     */
797    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
798
799    /**
800     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
801     * {@link WifiManager#WIFI_AP_STATE_DISABLING},
802     * {@link WifiManager#WIFI_AP_STATE_ENABLED},
803     * {@link WifiManager#WIFI_AP_STATE_ENABLING},
804     * {@link WifiManager#WIFI_AP_STATE_FAILED}
805     */
806    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
807
808    /**
809     * Work source to use to blame usage on the WiFi service
810     */
811    public static final WorkSource WIFI_WORK_SOURCE = new WorkSource(Process.WIFI_UID);
812
813    /**
814     * Keep track of whether WIFI is running.
815     */
816    private boolean mIsRunning = false;
817
818    /**
819     * Keep track of whether we last told the battery stats we had started.
820     */
821    private boolean mReportedRunning = false;
822
823    /**
824     * Most recently set source of starting WIFI.
825     */
826    private final WorkSource mRunningWifiUids = new WorkSource();
827
828    /**
829     * The last reported UIDs that were responsible for starting WIFI.
830     */
831    private final WorkSource mLastRunningWifiUids = new WorkSource();
832
833    private TelephonyManager mTelephonyManager;
834    private TelephonyManager getTelephonyManager() {
835        if (mTelephonyManager == null) {
836            mTelephonyManager = mWifiInjector.makeTelephonyManager();
837        }
838        return mTelephonyManager;
839    }
840
841    private final IBatteryStats mBatteryStats;
842
843    private final String mTcpBufferSizes;
844
845    // Used for debug and stats gathering
846    private static int sScanAlarmIntentCount = 0;
847
848    private FrameworkFacade mFacade;
849
850    private final BackupManagerProxy mBackupManagerProxy;
851
852    public WifiStateMachine(Context context, FrameworkFacade facade, Looper looper,
853                            UserManager userManager, WifiInjector wifiInjector,
854                            BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode,
855                            WifiNative wifiNative) {
856        super("WifiStateMachine", looper);
857        mWifiInjector = wifiInjector;
858        mWifiMetrics = mWifiInjector.getWifiMetrics();
859        mClock = wifiInjector.getClock();
860        mPropertyService = wifiInjector.getPropertyService();
861        mBuildProperties = wifiInjector.getBuildProperties();
862        mContext = context;
863        mFacade = facade;
864        mWifiNative = wifiNative;
865        mBackupManagerProxy = backupManagerProxy;
866
867        // TODO refactor WifiNative use of context out into it's own class
868        mWifiNative.initContext(mContext);
869        mInterfaceName = mWifiNative.getInterfaceName();
870        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
871        mBatteryStats = IBatteryStats.Stub.asInterface(mFacade.getService(
872                BatteryStats.SERVICE_NAME));
873
874        IBinder b = mFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
875        mNwService = INetworkManagementService.Stub.asInterface(b);
876
877        mP2pSupported = mContext.getPackageManager().hasSystemFeature(
878                PackageManager.FEATURE_WIFI_DIRECT);
879        mAwareSupported = mContext.getPackageManager()
880                .hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
881
882        mWifiConfigManager = mWifiInjector.getWifiConfigManager();
883        mWifiSupplicantControl = mWifiInjector.getWifiSupplicantControl();
884
885        mPasspointManager = mWifiInjector.getPasspointManager();
886
887        mWifiMonitor = WifiMonitor.getInstance();
888        mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative);
889
890        mWifiInfo = new WifiInfo();
891        mWifiNetworkSelector = mWifiInjector.getWifiNetworkSelector();
892        mSupplicantStateTracker =
893                mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
894
895        mLinkProperties = new LinkProperties();
896
897        IBinder s1 = mFacade.getService(Context.WIFI_P2P_SERVICE);
898        mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1);
899
900        if (mAwareSupported) {
901            mWifiAwareManager = mContext.getSystemService(WifiAwareManager.class);
902        }
903
904        mNetworkInfo.setIsAvailable(false);
905        mLastBssid = null;
906        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
907        mLastSignalLevel = -1;
908
909        mIpManager = mFacade.makeIpManager(mContext, mInterfaceName, new IpManagerCallback());
910        mIpManager.setMulticastFilter(true);
911
912        mNoNetworksPeriodicScan = mContext.getResources().getInteger(
913                R.integer.config_wifi_no_network_periodic_scan_interval);
914
915        // TODO: remove these settings from the config file since we no longer obey them
916        // mContext.getResources().getInteger(R.integer.config_wifi_framework_scan_interval);
917        // mContext.getResources().getBoolean(R.bool.config_wifi_background_scan_support);
918
919        mPrimaryDeviceType = mContext.getResources().getString(
920                R.string.config_wifi_p2p_device_type);
921
922        mCountryCode = countryCode;
923
924        mWifiScoreReport = new WifiScoreReport(mContext, mWifiConfigManager);
925
926        mUserWantsSuspendOpt.set(mFacade.getIntegerSetting(mContext,
927                Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
928
929        mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
930        mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
931        mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
932        mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
933        mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
934        mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
935        // TODO - needs to be a bit more dynamic
936        mDfltNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
937
938        IntentFilter filter = new IntentFilter();
939        filter.addAction(Intent.ACTION_SCREEN_ON);
940        filter.addAction(Intent.ACTION_SCREEN_OFF);
941        mContext.registerReceiver(
942                new BroadcastReceiver() {
943                    @Override
944                    public void onReceive(Context context, Intent intent) {
945                        String action = intent.getAction();
946
947                        if (action.equals(Intent.ACTION_SCREEN_ON)) {
948                            sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
949                        } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
950                            sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
951                        }
952                    }
953                }, filter);
954
955        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
956                        Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
957                new ContentObserver(getHandler()) {
958                    @Override
959                    public void onChange(boolean selfChange) {
960                        mUserWantsSuspendOpt.set(mFacade.getIntegerSetting(mContext,
961                                Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
962                    }
963                });
964
965        mContext.registerReceiver(
966                new BroadcastReceiver() {
967                    @Override
968                    public void onReceive(Context context, Intent intent) {
969                        sendMessage(CMD_BOOT_COMPLETED);
970                    }
971                },
972                new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
973
974        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
975        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
976
977        mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
978        mSuspendWakeLock.setReferenceCounted(false);
979
980        mTcpBufferSizes = mContext.getResources().getString(
981                com.android.internal.R.string.config_wifi_tcp_buffers);
982
983        // Load Device configs
984        mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
985                R.bool.config_wifi_framework_enable_associated_network_selection);
986        mThresholdQualifiedRssi24 = context.getResources().getInteger(
987                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
988        mThresholdQualifiedRssi5 = context.getResources().getInteger(
989                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
990        mThresholdSaturatedRssi24 = context.getResources().getInteger(
991                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
992        mThresholdSaturatedRssi5 = context.getResources().getInteger(
993                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
994        mThresholdMinimumRssi5 = context.getResources().getInteger(
995                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
996        mThresholdMinimumRssi24 = context.getResources().getInteger(
997                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
998        mEnableLinkDebouncing = mContext.getResources().getBoolean(
999                R.bool.config_wifi_enable_disconnection_debounce);
1000        mEnableChipWakeUpWhenAssociated = true;
1001        mEnableRssiPollWhenAssociated = true;
1002
1003        // CHECKSTYLE:OFF IndentationCheck
1004        addState(mDefaultState);
1005            addState(mInitialState, mDefaultState);
1006            addState(mSupplicantStartingState, mDefaultState);
1007            addState(mSupplicantStartedState, mDefaultState);
1008                    addState(mScanModeState, mSupplicantStartedState);
1009                    addState(mConnectModeState, mSupplicantStartedState);
1010                        addState(mL2ConnectedState, mConnectModeState);
1011                            addState(mObtainingIpState, mL2ConnectedState);
1012                            addState(mConnectedState, mL2ConnectedState);
1013                            addState(mRoamingState, mL2ConnectedState);
1014                        addState(mDisconnectingState, mConnectModeState);
1015                        addState(mDisconnectedState, mConnectModeState);
1016                        addState(mWpsRunningState, mConnectModeState);
1017                addState(mWaitForP2pDisableState, mSupplicantStartedState);
1018            addState(mSupplicantStoppingState, mDefaultState);
1019            addState(mSoftApState, mDefaultState);
1020        // CHECKSTYLE:ON IndentationCheck
1021
1022        setInitialState(mInitialState);
1023
1024        setLogRecSize(NUM_LOG_RECS_NORMAL);
1025        setLogOnlyTransitions(false);
1026
1027        // Clean up existing interfaces in wificond.
1028        // This ensures that wificond continue to work if java framework restarts.
1029        try {
1030            mWificond = mWifiInjector.makeWificond();
1031            if (mWificond != null) {
1032                mWificond.tearDownInterfaces();
1033            }
1034        } catch (RemoteException e) {
1035            // There is very little we can do here
1036            Log.e(TAG, "Failed to tear down interfaces via wificond");
1037        }
1038
1039        //start the state machine
1040        start();
1041
1042        // Learn the initial state of whether the screen is on.
1043        // We update this field when we receive broadcasts from the system.
1044        handleScreenStateChanged(powerManager.isInteractive());
1045
1046        mWifiMonitor.registerHandler(mInterfaceName, CMD_TARGET_BSSID, getHandler());
1047        mWifiMonitor.registerHandler(mInterfaceName, CMD_ASSOCIATED_BSSID, getHandler());
1048        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ANQP_DONE_EVENT, getHandler());
1049        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
1050                getHandler());
1051        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
1052                getHandler());
1053        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.DRIVER_HUNG_EVENT, getHandler());
1054        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_DONE_EVENT, getHandler());
1055        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.GAS_QUERY_START_EVENT,
1056                getHandler());
1057        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.HS20_REMEDIATION_EVENT,
1058                getHandler());
1059        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
1060                getHandler());
1061        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
1062                getHandler());
1063        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
1064                getHandler());
1065        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_FAILED_EVENT, getHandler());
1066        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_RESULTS_EVENT, getHandler());
1067        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SSID_REENABLED, getHandler());
1068        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SSID_TEMP_DISABLED, getHandler());
1069        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
1070        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_DISCONNECTION_EVENT,
1071                getHandler());
1072        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
1073                getHandler());
1074        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_IDENTITY, getHandler());
1075        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_SIM_AUTH, getHandler());
1076        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_FAIL_EVENT, getHandler());
1077        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_OVERLAP_EVENT, getHandler());
1078        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_SUCCESS_EVENT, getHandler());
1079        mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_TIMEOUT_EVENT, getHandler());
1080
1081        final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
1082        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1083        intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
1084        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1085    }
1086
1087    class IpManagerCallback extends IpManager.Callback {
1088        @Override
1089        public void onPreDhcpAction() {
1090            sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
1091        }
1092
1093        @Override
1094        public void onPostDhcpAction() {
1095            sendMessage(DhcpClient.CMD_POST_DHCP_ACTION);
1096        }
1097
1098        @Override
1099        public void onNewDhcpResults(DhcpResults dhcpResults) {
1100            if (dhcpResults != null) {
1101                sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, dhcpResults);
1102            } else {
1103                sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
1104                mWifiInjector.getWifiLastResortWatchdog().noteConnectionFailureAndTriggerIfNeeded(
1105                        getTargetSsid(), mTargetRoamBSSID,
1106                        WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1107            }
1108        }
1109
1110        @Override
1111        public void onProvisioningSuccess(LinkProperties newLp) {
1112            sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1113            sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
1114        }
1115
1116        @Override
1117        public void onProvisioningFailure(LinkProperties newLp) {
1118            sendMessage(CMD_IP_CONFIGURATION_LOST);
1119        }
1120
1121        @Override
1122        public void onLinkPropertiesChange(LinkProperties newLp) {
1123            sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
1124        }
1125
1126        @Override
1127        public void onReachabilityLost(String logMsg) {
1128            sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
1129        }
1130
1131        @Override
1132        public void installPacketFilter(byte[] filter) {
1133            sendMessage(CMD_INSTALL_PACKET_FILTER, filter);
1134        }
1135
1136        @Override
1137        public void setFallbackMulticastFilter(boolean enabled) {
1138            sendMessage(CMD_SET_FALLBACK_PACKET_FILTERING, enabled);
1139        }
1140
1141        @Override
1142        public void setNeighborDiscoveryOffload(boolean enabled) {
1143            sendMessage(CMD_CONFIG_ND_OFFLOAD, (enabled ? 1 : 0));
1144        }
1145    }
1146
1147    private void stopIpManager() {
1148        /* Restore power save and suspend optimizations */
1149        handlePostDhcpSetup();
1150        mIpManager.stop();
1151    }
1152
1153    PendingIntent getPrivateBroadcast(String action, int requestCode) {
1154        Intent intent = new Intent(action, null);
1155        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1156        intent.setPackage("android");
1157        return mFacade.getBroadcast(mContext, requestCode, intent, 0);
1158    }
1159
1160    /**
1161     * Set wpa_supplicant log level using |mVerboseLoggingLevel| flag.
1162     */
1163    void setSupplicantLogLevel() {
1164        if (mVerboseLoggingEnabled) {
1165            mWifiNative.setSupplicantLogLevel("DEBUG");
1166        } else {
1167            mWifiNative.setSupplicantLogLevel("INFO");
1168        }
1169    }
1170
1171    void enableVerboseLogging(int verbose) {
1172        if (verbose > 0) {
1173            mVerboseLoggingEnabled = true;
1174            setLogRecSize(ActivityManager.isLowRamDeviceStatic()
1175                    ? NUM_LOG_RECS_VERBOSE_LOW_MEMORY : NUM_LOG_RECS_VERBOSE);
1176        } else {
1177            mVerboseLoggingEnabled = false;
1178            setLogRecSize(NUM_LOG_RECS_NORMAL);
1179        }
1180        configureVerboseHalLogging(mVerboseLoggingEnabled);
1181        setSupplicantLogLevel();
1182        mCountryCode.enableVerboseLogging(verbose);
1183        mWifiScoreReport.enableVerboseLogging(mVerboseLoggingEnabled);
1184        mWifiDiagnostics.startLogging(mVerboseLoggingEnabled);
1185        mWifiMonitor.enableVerboseLogging(verbose);
1186        mWifiNative.enableVerboseLogging(verbose);
1187        mWifiConfigManager.enableVerboseLogging(verbose);
1188        mSupplicantStateTracker.enableVerboseLogging(verbose);
1189    }
1190
1191    private static final String SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL = "log.tag.WifiHAL";
1192    private static final String LOGD_LEVEL_DEBUG = "D";
1193    private static final String LOGD_LEVEL_VERBOSE = "V";
1194    private void configureVerboseHalLogging(boolean enableVerbose) {
1195        if (mBuildProperties.isUserBuild()) {  // Verbose HAL logging not supported on user builds.
1196            return;
1197        }
1198        mPropertyService.set(SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL,
1199                enableVerbose ? LOGD_LEVEL_VERBOSE : LOGD_LEVEL_DEBUG);
1200    }
1201
1202    private int mAggressiveHandover = 0;
1203
1204    int getAggressiveHandover() {
1205        return mAggressiveHandover;
1206    }
1207
1208    void enableAggressiveHandover(int enabled) {
1209        mAggressiveHandover = enabled;
1210    }
1211
1212    public void clearANQPCache() {
1213        // TODO(b/31065385)
1214        // mWifiConfigManager.trimANQPCache(true);
1215    }
1216
1217    public void setAllowScansWithTraffic(int enabled) {
1218        mAlwaysEnableScansWhileAssociated = enabled;
1219    }
1220
1221    public int getAllowScansWithTraffic() {
1222        return mAlwaysEnableScansWhileAssociated;
1223    }
1224
1225    /*
1226     * Dynamically turn on/off if switching networks while connected is allowd.
1227     */
1228    public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
1229        sendMessage(CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED, enabled ? 1 : 0);
1230        return true;
1231    }
1232
1233    public boolean getEnableAutoJoinWhenAssociated() {
1234        return mEnableAutoJoinWhenAssociated;
1235    }
1236
1237    private boolean setRandomMacOui() {
1238        String oui = mContext.getResources().getString(R.string.config_wifi_random_mac_oui);
1239        if (TextUtils.isEmpty(oui)) {
1240            oui = GOOGLE_OUI;
1241        }
1242        String[] ouiParts = oui.split("-");
1243        byte[] ouiBytes = new byte[3];
1244        ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF);
1245        ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF);
1246        ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF);
1247
1248        logd("Setting OUI to " + oui);
1249        return mWifiNative.setScanningMacOui(ouiBytes);
1250    }
1251
1252    /**
1253     * Helper method to lookup the framework network ID of the network currently configured in
1254     * wpa_supplicant using the provided supplicant network ID. This is needed for translating the
1255     * networkID received from all {@link WifiMonitor} events.
1256     *
1257     * @param supplicantNetworkId Network ID of network in wpa_supplicant.
1258     * @return Corresponding Internal configured network ID
1259     * TODO(b/31080843): This is ugly! We need to hide this translation of networkId's. This will
1260     * be handled once we move all of this connection logic to wificond.
1261     */
1262    private int lookupFrameworkNetworkId(int supplicantNetworkId) {
1263        return mWifiSupplicantControl.getFrameworkNetworkId(supplicantNetworkId);
1264    }
1265
1266    /**
1267     * Initiates connection to a network specified by the user/app. This method checks if the
1268     * requesting app holds the WIFI_CONFIG_OVERRIDE permission.
1269     * a) If yes, we start a new connection attempt to the specified network.
1270     * b) if no, then we ask connectivity manager to start a new scan and trigger network selection.
1271     */
1272    private boolean connectToUserSelectNetwork(int netId, int uid) {
1273        if (!mWifiConfigManager.enableNetwork(netId, true, uid)) {
1274            loge("connectToUserSelectNetwork uid " + uid
1275                    + " did not have the permissions to enable=" + netId);
1276            return false;
1277        }
1278        if (!mWifiConfigManager.checkAndUpdateLastConnectUid(netId, uid)) {
1279            loge("connectToUserSelectNetwork uid " + uid
1280                    + " did not have the permissions to connect=" + netId);
1281            // App does not have the permission to force a connection. But, we should still
1282            // reconsider this newly enabled network for network selection.
1283            mWifiConnectivityManager.forceConnectivityScan();
1284        } else {
1285            // Trigger an immediate connection to the specified network. We're also noting the user
1286            // connect choice here, so that it will be considered in the next network selection.
1287            mWifiConnectivityManager.setUserConnectChoice(netId);
1288            if (mWifiInfo.getNetworkId() == netId) {
1289                // We're already connected to the user specified network, don't trigger a
1290                // reconnection.
1291                logi("connectToUserSelectNetwork already connecting/connected=" + netId);
1292            } else {
1293                startConnectToNetwork(netId, SUPPLICANT_BSSID_ANY);
1294            }
1295        }
1296        return true;
1297    }
1298
1299    /**
1300     * ******************************************************
1301     * Methods exposed for public use
1302     * ******************************************************
1303     */
1304
1305    public Messenger getMessenger() {
1306        return new Messenger(getHandler());
1307    }
1308
1309    /**
1310     * TODO: doc
1311     */
1312    public boolean syncPingSupplicant(AsyncChannel channel) {
1313        Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
1314        boolean result = (resultMsg.arg1 != FAILURE);
1315        resultMsg.recycle();
1316        return result;
1317    }
1318
1319    /**
1320     * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
1321     * given to callingUid.
1322     *
1323     * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
1324     *                   workSource is specified.
1325     * @param workSource If not null, blame is given to workSource.
1326     * @param settings   Scan settings, see {@link ScanSettings}.
1327     */
1328    public void startScan(int callingUid, int scanCounter,
1329                          ScanSettings settings, WorkSource workSource) {
1330        Bundle bundle = new Bundle();
1331        bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
1332        bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1333        bundle.putLong(SCAN_REQUEST_TIME, mClock.getWallClockMillis());
1334        sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
1335    }
1336
1337    private long mDisconnectedTimeStamp = 0;
1338
1339    public long getDisconnectedTimeMilli() {
1340        if (getCurrentState() == mDisconnectedState
1341                && mDisconnectedTimeStamp != 0) {
1342            long now_ms = mClock.getWallClockMillis();
1343            return now_ms - mDisconnectedTimeStamp;
1344        }
1345        return 0;
1346    }
1347
1348    // Last connect attempt is used to prevent scan requests:
1349    //  - for a period of 10 seconds after attempting to connect
1350    private long lastConnectAttemptTimestamp = 0;
1351    private Set<Integer> lastScanFreqs = null;
1352
1353    // For debugging, keep track of last message status handling
1354    // TODO, find an equivalent mechanism as part of parent class
1355    private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
1356    private static int MESSAGE_HANDLING_STATUS_OK = 1;
1357    private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
1358    private static int MESSAGE_HANDLING_STATUS_REFUSED = -1;
1359    private static int MESSAGE_HANDLING_STATUS_FAIL = -2;
1360    private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
1361    private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
1362    private static int MESSAGE_HANDLING_STATUS_DISCARD = -5;
1363    private static int MESSAGE_HANDLING_STATUS_LOOPED = -6;
1364    private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
1365
1366    private int messageHandlingStatus = 0;
1367
1368    //TODO: this is used only to track connection attempts, however the link state and packet per
1369    //TODO: second logic should be folded into that
1370    private boolean checkOrDeferScanAllowed(Message msg) {
1371        long now = mClock.getWallClockMillis();
1372        if (lastConnectAttemptTimestamp != 0 && (now - lastConnectAttemptTimestamp) < 10000) {
1373            Message dmsg = Message.obtain(msg);
1374            sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttemptTimestamp));
1375            return false;
1376        }
1377        return true;
1378    }
1379
1380    private int mOnTime = 0;
1381    private int mTxTime = 0;
1382    private int mRxTime = 0;
1383
1384    private int mOnTimeScreenStateChange = 0;
1385    private long lastOntimeReportTimeStamp = 0;
1386    private long lastScreenStateChangeTimeStamp = 0;
1387    private int mOnTimeLastReport = 0;
1388    private int mTxTimeLastReport = 0;
1389    private int mRxTimeLastReport = 0;
1390
1391    private long lastLinkLayerStatsUpdate = 0;
1392
1393    String reportOnTime() {
1394        long now = mClock.getWallClockMillis();
1395        StringBuilder sb = new StringBuilder();
1396        // Report stats since last report
1397        int on = mOnTime - mOnTimeLastReport;
1398        mOnTimeLastReport = mOnTime;
1399        int tx = mTxTime - mTxTimeLastReport;
1400        mTxTimeLastReport = mTxTime;
1401        int rx = mRxTime - mRxTimeLastReport;
1402        mRxTimeLastReport = mRxTime;
1403        int period = (int) (now - lastOntimeReportTimeStamp);
1404        lastOntimeReportTimeStamp = now;
1405        sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
1406        // Report stats since Screen State Changed
1407        on = mOnTime - mOnTimeScreenStateChange;
1408        period = (int) (now - lastScreenStateChangeTimeStamp);
1409        sb.append(String.format(" from screen [on:%d period:%d]", on, period));
1410        return sb.toString();
1411    }
1412
1413    WifiLinkLayerStats getWifiLinkLayerStats() {
1414        WifiLinkLayerStats stats = null;
1415        if (mWifiLinkLayerStatsSupported > 0) {
1416            String name = "wlan0";
1417            stats = mWifiNative.getWifiLinkLayerStats(name);
1418            if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
1419                mWifiLinkLayerStatsSupported -= 1;
1420            } else if (stats != null) {
1421                lastLinkLayerStatsUpdate = mClock.getWallClockMillis();
1422                mOnTime = stats.on_time;
1423                mTxTime = stats.tx_time;
1424                mRxTime = stats.rx_time;
1425                mRunningBeaconCount = stats.beacon_rx;
1426            }
1427        }
1428        if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
1429            long mTxPkts = mFacade.getTxPackets(mInterfaceName);
1430            long mRxPkts = mFacade.getRxPackets(mInterfaceName);
1431            mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
1432        } else {
1433            mWifiInfo.updatePacketRates(stats);
1434        }
1435        return stats;
1436    }
1437
1438    int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds) {
1439        int ret = mWifiNative.startSendingOffloadedPacket(slot, packetData, intervalSeconds * 1000);
1440        if (ret != 0) {
1441            loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds +
1442                    "): hardware error " + ret);
1443            return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
1444        } else {
1445            return ConnectivityManager.PacketKeepalive.SUCCESS;
1446        }
1447    }
1448
1449    int stopWifiIPPacketOffload(int slot) {
1450        int ret = mWifiNative.stopSendingOffloadedPacket(slot);
1451        if (ret != 0) {
1452            loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret);
1453            return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
1454        } else {
1455            return ConnectivityManager.PacketKeepalive.SUCCESS;
1456        }
1457    }
1458
1459    int startRssiMonitoringOffload(byte maxRssi, byte minRssi) {
1460        return mWifiNative.startRssiMonitoring(maxRssi, minRssi, WifiStateMachine.this);
1461    }
1462
1463    int stopRssiMonitoringOffload() {
1464        return mWifiNative.stopRssiMonitoring();
1465    }
1466
1467    private void handleScanRequest(Message message) {
1468        ScanSettings settings = null;
1469        WorkSource workSource = null;
1470
1471        // unbundle parameters
1472        Bundle bundle = (Bundle) message.obj;
1473
1474        if (bundle != null) {
1475            settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
1476            workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
1477        }
1478
1479        Set<Integer> freqs = null;
1480        if (settings != null && settings.channelSet != null) {
1481            freqs = new HashSet<>();
1482            for (WifiChannel channel : settings.channelSet) {
1483                freqs.add(channel.freqMHz);
1484            }
1485        }
1486
1487        // Retrieve the list of hidden network SSIDs to scan for.
1488        List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks =
1489                mWifiConfigManager.retrieveHiddenNetworkList();
1490
1491        // call wifi native to start the scan
1492        if (startScanNative(freqs, hiddenNetworks, workSource)) {
1493            // a full scan covers everything, clearing scan request buffer
1494            if (freqs == null)
1495                mBufferedScanMsg.clear();
1496            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
1497            return;
1498        }
1499
1500        // if reach here, scan request is rejected
1501
1502        if (!mIsScanOngoing) {
1503            // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
1504
1505            // discard this request and pop up the next one
1506            if (mBufferedScanMsg.size() > 0) {
1507                sendMessage(mBufferedScanMsg.remove());
1508            }
1509            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
1510        } else if (!mIsFullScanOngoing) {
1511            // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
1512            // buffer the scan request to make sure specified channels will be scanned eventually
1513            if (freqs == null)
1514                mBufferedScanMsg.clear();
1515            if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
1516                Message msg = obtainMessage(CMD_START_SCAN,
1517                        message.arg1, message.arg2, bundle);
1518                mBufferedScanMsg.add(msg);
1519            } else {
1520                // if too many requests in buffer, combine them into a single full scan
1521                bundle = new Bundle();
1522                bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
1523                bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1524                Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
1525                mBufferedScanMsg.clear();
1526                mBufferedScanMsg.add(msg);
1527            }
1528            messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
1529        } else {
1530            // mIsScanOngoing and mIsFullScanOngoing
1531            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
1532        }
1533    }
1534
1535
1536    // TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
1537    // scan functionality is refactored out of WifiStateMachine.
1538    /**
1539     * return true iff scan request is accepted
1540     */
1541    private boolean startScanNative(final Set<Integer> freqs,
1542            List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList,
1543            WorkSource workSource) {
1544        WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
1545        if (freqs == null) {
1546            settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
1547        } else {
1548            settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
1549            int index = 0;
1550            settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
1551            for (Integer freq : freqs) {
1552                settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
1553            }
1554        }
1555        settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
1556                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
1557
1558        settings.hiddenNetworks =
1559                hiddenNetworkList.toArray(
1560                        new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
1561
1562        WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
1563                // ignore all events since WifiStateMachine is registered for the supplicant events
1564                @Override
1565                public void onSuccess() {
1566                }
1567                @Override
1568                public void onFailure(int reason, String description) {
1569                    mIsScanOngoing = false;
1570                    mIsFullScanOngoing = false;
1571                }
1572                @Override
1573                public void onResults(WifiScanner.ScanData[] results) {
1574                }
1575                @Override
1576                public void onFullResult(ScanResult fullScanResult) {
1577                }
1578                @Override
1579                public void onPeriodChanged(int periodInMs) {
1580                }
1581            };
1582        mWifiScanner.startScan(settings, nativeScanListener, workSource);
1583        mIsScanOngoing = true;
1584        mIsFullScanOngoing = (freqs == null);
1585        lastScanFreqs = freqs;
1586        return true;
1587    }
1588
1589    /**
1590     * TODO: doc
1591     */
1592    public void setSupplicantRunning(boolean enable) {
1593        if (enable) {
1594            sendMessage(CMD_START_SUPPLICANT);
1595        } else {
1596            sendMessage(CMD_STOP_SUPPLICANT);
1597        }
1598    }
1599
1600    /**
1601     * TODO: doc
1602     */
1603    public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
1604        if (enable) {
1605            sendMessage(CMD_START_AP, wifiConfig);
1606        } else {
1607            sendMessage(CMD_STOP_AP);
1608        }
1609    }
1610
1611    public void setWifiApConfiguration(WifiConfiguration config) {
1612        mWifiApConfigStore.setApConfiguration(config);
1613    }
1614
1615    public WifiConfiguration syncGetWifiApConfiguration() {
1616        return mWifiApConfigStore.getApConfiguration();
1617    }
1618
1619    /**
1620     * TODO: doc
1621     */
1622    public int syncGetWifiState() {
1623        return mWifiState.get();
1624    }
1625
1626    /**
1627     * TODO: doc
1628     */
1629    public String syncGetWifiStateByName() {
1630        switch (mWifiState.get()) {
1631            case WIFI_STATE_DISABLING:
1632                return "disabling";
1633            case WIFI_STATE_DISABLED:
1634                return "disabled";
1635            case WIFI_STATE_ENABLING:
1636                return "enabling";
1637            case WIFI_STATE_ENABLED:
1638                return "enabled";
1639            case WIFI_STATE_UNKNOWN:
1640                return "unknown state";
1641            default:
1642                return "[invalid state]";
1643        }
1644    }
1645
1646    /**
1647     * TODO: doc
1648     */
1649    public int syncGetWifiApState() {
1650        return mWifiApState.get();
1651    }
1652
1653    /**
1654     * TODO: doc
1655     */
1656    public String syncGetWifiApStateByName() {
1657        switch (mWifiApState.get()) {
1658            case WIFI_AP_STATE_DISABLING:
1659                return "disabling";
1660            case WIFI_AP_STATE_DISABLED:
1661                return "disabled";
1662            case WIFI_AP_STATE_ENABLING:
1663                return "enabling";
1664            case WIFI_AP_STATE_ENABLED:
1665                return "enabled";
1666            case WIFI_AP_STATE_FAILED:
1667                return "failed";
1668            default:
1669                return "[invalid state]";
1670        }
1671    }
1672
1673    public boolean isConnected() {
1674        return getCurrentState() == mConnectedState;
1675    }
1676
1677    public boolean isDisconnected() {
1678        return getCurrentState() == mDisconnectedState;
1679    }
1680
1681    public boolean isSupplicantTransientState() {
1682        SupplicantState supplicantState = mWifiInfo.getSupplicantState();
1683        if (supplicantState == SupplicantState.ASSOCIATING
1684                || supplicantState == SupplicantState.AUTHENTICATING
1685                || supplicantState == SupplicantState.FOUR_WAY_HANDSHAKE
1686                || supplicantState == SupplicantState.GROUP_HANDSHAKE) {
1687
1688            if (mVerboseLoggingEnabled) {
1689                Log.d(TAG, "Supplicant is under transient state: " + supplicantState);
1690            }
1691            return true;
1692        } else {
1693            if (mVerboseLoggingEnabled) {
1694                Log.d(TAG, "Supplicant is under steady state: " + supplicantState);
1695            }
1696        }
1697
1698        return false;
1699    }
1700
1701    public boolean isLinkDebouncing() {
1702        return mIsLinkDebouncing;
1703    }
1704
1705    /**
1706     * Get status information for the current connection, if any.
1707     *
1708     * @return a {@link WifiInfo} object containing information about the current connection
1709     */
1710    public WifiInfo syncRequestConnectionInfo() {
1711        return getWiFiInfoForUid(Binder.getCallingUid());
1712    }
1713
1714    public WifiInfo getWifiInfo() {
1715        return mWifiInfo;
1716    }
1717
1718    public DhcpResults syncGetDhcpResults() {
1719        synchronized (mDhcpResultsLock) {
1720            return new DhcpResults(mDhcpResults);
1721        }
1722    }
1723
1724    /**
1725     * TODO: doc
1726     */
1727    public void setOperationalMode(int mode) {
1728        if (mVerboseLoggingEnabled) log("setting operational mode to " + String.valueOf(mode));
1729        sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
1730    }
1731
1732    /**
1733     * Allow tests to confirm the operational mode for WSM.
1734     */
1735    @VisibleForTesting
1736    protected int getOperationalModeForTest() {
1737        return mOperationalMode;
1738    }
1739
1740    /**
1741     * TODO: doc
1742     */
1743    public List<ScanResult> syncGetScanResultsList() {
1744        synchronized (mScanResultsLock) {
1745            List<ScanResult> scanList = new ArrayList<>();
1746            for (ScanDetail result : mScanResults) {
1747                scanList.add(new ScanResult(result.getScanResult()));
1748            }
1749            return scanList;
1750        }
1751    }
1752
1753    public int syncAddPasspointManagementObject(AsyncChannel channel, String managementObject) {
1754        Message resultMsg =
1755                channel.sendMessageSynchronously(CMD_ADD_PASSPOINT_MO, managementObject);
1756        int result = resultMsg.arg1;
1757        resultMsg.recycle();
1758        return result;
1759    }
1760
1761    public int syncModifyPasspointManagementObject(AsyncChannel channel, String fqdn,
1762                                                   List<PasspointManagementObjectDefinition>
1763                                                           managementObjectDefinitions) {
1764        Bundle bundle = new Bundle();
1765        bundle.putString("FQDN", fqdn);
1766        bundle.putParcelableList("MOS", managementObjectDefinitions);
1767        Message resultMsg = channel.sendMessageSynchronously(CMD_MODIFY_PASSPOINT_MO, bundle);
1768        int result = resultMsg.arg1;
1769        resultMsg.recycle();
1770        return result;
1771    }
1772
1773    public boolean syncQueryPasspointIcon(AsyncChannel channel, long bssid, String fileName) {
1774        Bundle bundle = new Bundle();
1775        bundle.putLong(EXTRA_OSU_ICON_QUERY_BSSID, bssid);
1776        bundle.putString(EXTRA_OSU_ICON_QUERY_FILENAME, fileName);
1777        Message resultMsg = channel.sendMessageSynchronously(CMD_QUERY_OSU_ICON, bundle);
1778        int result = resultMsg.arg1;
1779        resultMsg.recycle();
1780        return result == 1;
1781    }
1782
1783    public int matchProviderWithCurrentNetwork(AsyncChannel channel, String fqdn) {
1784        Message resultMsg = channel.sendMessageSynchronously(CMD_MATCH_PROVIDER_NETWORK, fqdn);
1785        int result = resultMsg.arg1;
1786        resultMsg.recycle();
1787        return result;
1788    }
1789
1790    /**
1791     * Deauthenticate and set the re-authentication hold off time for the current network
1792     * @param holdoff hold off time in milliseconds
1793     * @param ess set if the hold off pertains to an ESS rather than a BSS
1794     */
1795    public void deauthenticateNetwork(AsyncChannel channel, long holdoff, boolean ess) {
1796        // TODO: This needs an implementation
1797    }
1798
1799    public void disableEphemeralNetwork(String SSID) {
1800        if (SSID != null) {
1801            sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID);
1802        }
1803    }
1804
1805    /**
1806     * Disconnect from Access Point
1807     */
1808    public void disconnectCommand() {
1809        sendMessage(CMD_DISCONNECT);
1810    }
1811
1812    public void disconnectCommand(int uid, int reason) {
1813        sendMessage(CMD_DISCONNECT, uid, reason);
1814    }
1815
1816    /**
1817     * Initiate a reconnection to AP
1818     */
1819    public void reconnectCommand() {
1820        sendMessage(CMD_RECONNECT);
1821    }
1822
1823    /**
1824     * Initiate a re-association to AP
1825     */
1826    public void reassociateCommand() {
1827        sendMessage(CMD_REASSOCIATE);
1828    }
1829
1830    /**
1831     * Reload networks and then reconnect; helps load correct data for TLS networks
1832     */
1833
1834    public void reloadTlsNetworksAndReconnect() {
1835        sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
1836    }
1837
1838    /**
1839     * Add a network synchronously
1840     *
1841     * @return network id of the new network
1842     */
1843    public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
1844        Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
1845        int result = resultMsg.arg1;
1846        resultMsg.recycle();
1847        return result;
1848    }
1849
1850    /**
1851     * Get configured networks synchronously
1852     *
1853     * @param channel
1854     * @return
1855     */
1856
1857    public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
1858        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
1859        List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
1860        resultMsg.recycle();
1861        return result;
1862    }
1863
1864    public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
1865        Message resultMsg = channel.sendMessageSynchronously(
1866                CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS);
1867        List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
1868        resultMsg.recycle();
1869        return result;
1870    }
1871
1872    public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) {
1873        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult);
1874        return (WifiConfiguration) resultMsg.obj;
1875    }
1876
1877    /**
1878     * Get connection statistics synchronously
1879     *
1880     * @param channel
1881     * @return
1882     */
1883
1884    public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) {
1885        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS);
1886        WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj;
1887        resultMsg.recycle();
1888        return result;
1889    }
1890
1891    /**
1892     * Get adaptors synchronously
1893     */
1894
1895    public int syncGetSupportedFeatures(AsyncChannel channel) {
1896        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
1897        int supportedFeatureSet = resultMsg.arg1;
1898        resultMsg.recycle();
1899
1900        // Mask the feature set against system properties.
1901        boolean disableRtt = mPropertyService.getBoolean("config.disable_rtt", false);
1902        if (disableRtt) {
1903            supportedFeatureSet &=
1904                    ~(WifiManager.WIFI_FEATURE_D2D_RTT | WifiManager.WIFI_FEATURE_D2AP_RTT);
1905        }
1906
1907        return supportedFeatureSet;
1908    }
1909
1910    /**
1911     * Get link layers stats for adapter synchronously
1912     */
1913    public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
1914        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
1915        WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
1916        resultMsg.recycle();
1917        return result;
1918    }
1919
1920    /**
1921     * Delete a network
1922     *
1923     * @param networkId id of the network to be removed
1924     */
1925    public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
1926        Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
1927        boolean result = (resultMsg.arg1 != FAILURE);
1928        resultMsg.recycle();
1929        return result;
1930    }
1931
1932    /**
1933     * Enable a network
1934     *
1935     * @param netId         network id of the network
1936     * @param disableOthers true, if all other networks have to be disabled
1937     * @return {@code true} if the operation succeeds, {@code false} otherwise
1938     */
1939    public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
1940        Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
1941                disableOthers ? 1 : 0);
1942        boolean result = (resultMsg.arg1 != FAILURE);
1943        resultMsg.recycle();
1944        return result;
1945    }
1946
1947    /**
1948     * Disable a network
1949     *
1950     * @param netId network id of the network
1951     * @return {@code true} if the operation succeeds, {@code false} otherwise
1952     */
1953    public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
1954        Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
1955        boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
1956        resultMsg.recycle();
1957        return result;
1958    }
1959
1960    /**
1961     * Retrieves a WPS-NFC configuration token for the specified network
1962     *
1963     * @return a hex string representation of the WPS-NFC configuration token
1964     */
1965    public String syncGetWpsNfcConfigurationToken(int netId) {
1966        return mWifiNative.getNfcWpsConfigurationToken(netId);
1967    }
1968
1969    public void enableRssiPolling(boolean enabled) {
1970        sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
1971    }
1972
1973    /**
1974     * Start filtering Multicast v4 packets
1975     */
1976    public void startFilteringMulticastPackets() {
1977        mIpManager.setMulticastFilter(true);
1978    }
1979
1980    /**
1981     * Stop filtering Multicast v4 packets
1982     */
1983    public void stopFilteringMulticastPackets() {
1984        mIpManager.setMulticastFilter(false);
1985    }
1986
1987    /**
1988     * Set high performance mode of operation.
1989     * Enabling would set active power mode and disable suspend optimizations;
1990     * disabling would set auto power mode and enable suspend optimizations
1991     *
1992     * @param enable true if enable, false otherwise
1993     */
1994    public void setHighPerfModeEnabled(boolean enable) {
1995        sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
1996    }
1997
1998
1999    /**
2000     * reset cached SIM credential data
2001     */
2002    public synchronized void resetSimAuthNetworks(boolean simPresent) {
2003        sendMessage(CMD_RESET_SIM_NETWORKS, simPresent ? 1 : 0);
2004    }
2005
2006    /**
2007     * Get Network object of current wifi network
2008     * @return Network object of current wifi network
2009     */
2010    public Network getCurrentNetwork() {
2011        if (mNetworkAgent != null) {
2012            return new Network(mNetworkAgent.netId);
2013        } else {
2014            return null;
2015        }
2016    }
2017
2018    /**
2019     * Enable TDLS for a specific MAC address
2020     */
2021    public void enableTdls(String remoteMacAddress, boolean enable) {
2022        int enabler = enable ? 1 : 0;
2023        sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
2024    }
2025
2026    /**
2027     * Send a message indicating bluetooth adapter connection state changed
2028     */
2029    public void sendBluetoothAdapterStateChange(int state) {
2030        sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
2031    }
2032
2033    /**
2034     * Send a message indicating a package has been uninstalled.
2035     */
2036    public void removeAppConfigs(String packageName, int uid) {
2037        // Build partial AppInfo manually - package may not exist in database any more
2038        ApplicationInfo ai = new ApplicationInfo();
2039        ai.packageName = packageName;
2040        ai.uid = uid;
2041        sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai);
2042    }
2043
2044    /**
2045     * Send a message indicating a user has been removed.
2046     */
2047    public void removeUserConfigs(int userId) {
2048        sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId);
2049    }
2050
2051    /**
2052     * Save configuration on supplicant
2053     *
2054     * @return {@code true} if the operation succeeds, {@code false} otherwise
2055     * <p/>
2056     * TODO: deprecate this
2057     */
2058    public boolean syncSaveConfig(AsyncChannel channel) {
2059        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
2060        boolean result = (resultMsg.arg1 != FAILURE);
2061        resultMsg.recycle();
2062        return result;
2063    }
2064
2065    public void updateBatteryWorkSource(WorkSource newSource) {
2066        synchronized (mRunningWifiUids) {
2067            try {
2068                if (newSource != null) {
2069                    mRunningWifiUids.set(newSource);
2070                }
2071                if (mIsRunning) {
2072                    if (mReportedRunning) {
2073                        // If the work source has changed since last time, need
2074                        // to remove old work from battery stats.
2075                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
2076                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
2077                                    mRunningWifiUids);
2078                            mLastRunningWifiUids.set(mRunningWifiUids);
2079                        }
2080                    } else {
2081                        // Now being started, report it.
2082                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
2083                        mLastRunningWifiUids.set(mRunningWifiUids);
2084                        mReportedRunning = true;
2085                    }
2086                } else {
2087                    if (mReportedRunning) {
2088                        // Last reported we were running, time to stop.
2089                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
2090                        mLastRunningWifiUids.clear();
2091                        mReportedRunning = false;
2092                    }
2093                }
2094                mWakeLock.setWorkSource(newSource);
2095            } catch (RemoteException ignore) {
2096            }
2097        }
2098    }
2099
2100    public void dumpIpManager(FileDescriptor fd, PrintWriter pw, String[] args) {
2101        mIpManager.dump(fd, pw, args);
2102    }
2103
2104    @Override
2105    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2106        if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
2107                && WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) {
2108            // Dump only wifi metrics serialized proto bytes (base64)
2109            updateWifiMetrics();
2110            mWifiMetrics.dump(fd, pw, args);
2111            return;
2112        }
2113        super.dump(fd, pw, args);
2114        mSupplicantStateTracker.dump(fd, pw, args);
2115        pw.println("mLinkProperties " + mLinkProperties);
2116        pw.println("mWifiInfo " + mWifiInfo);
2117        pw.println("mDhcpResults " + mDhcpResults);
2118        pw.println("mNetworkInfo " + mNetworkInfo);
2119        pw.println("mLastSignalLevel " + mLastSignalLevel);
2120        pw.println("mLastBssid " + mLastBssid);
2121        pw.println("mLastNetworkId " + mLastNetworkId);
2122        pw.println("mOperationalMode " + mOperationalMode);
2123        pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
2124        pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2125        pw.println("Supplicant status " + mWifiNative.status(true));
2126        if (mCountryCode.getCountryCodeSentToDriver() != null) {
2127            pw.println("CountryCode sent to driver " + mCountryCode.getCountryCodeSentToDriver());
2128        } else {
2129            if (mCountryCode.getCountryCode() != null) {
2130                pw.println("CountryCode: " +
2131                        mCountryCode.getCountryCode() + " was not sent to driver");
2132            } else {
2133                pw.println("CountryCode was not initialized");
2134            }
2135        }
2136        if (mNetworkFactory != null) {
2137            mNetworkFactory.dump(fd, pw, args);
2138        } else {
2139            pw.println("mNetworkFactory is not initialized");
2140        }
2141
2142        if (mUntrustedNetworkFactory != null) {
2143            mUntrustedNetworkFactory.dump(fd, pw, args);
2144        } else {
2145            pw.println("mUntrustedNetworkFactory is not initialized");
2146        }
2147        pw.println("Wlan Wake Reasons:" + mWifiNative.getWlanWakeReasonCount());
2148        pw.println();
2149        updateWifiMetrics();
2150        mWifiMetrics.dump(fd, pw, args);
2151        pw.println();
2152
2153        mWifiConfigManager.dump(fd, pw, args);
2154        pw.println();
2155        mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_USER_ACTION);
2156        mWifiDiagnostics.dump(fd, pw, args);
2157        dumpIpManager(fd, pw, args);
2158        mWifiNetworkSelector.dump(fd, pw, args);
2159    }
2160
2161    public void handleUserSwitch(int userId) {
2162        sendMessage(CMD_USER_SWITCH, userId);
2163    }
2164
2165    public void handleUserUnlock(int userId) {
2166        sendMessage(CMD_USER_UNLOCK, userId);
2167    }
2168
2169    public void handleUserStop(int userId) {
2170        sendMessage(CMD_USER_STOP, userId);
2171    }
2172
2173    /**
2174     * ******************************************************
2175     * Internal private functions
2176     * ******************************************************
2177     */
2178
2179    private void logStateAndMessage(Message message, State state) {
2180        messageHandlingStatus = 0;
2181        if (mVerboseLoggingEnabled) {
2182            logd(" " + state.getClass().getSimpleName() + " " + getLogRecString(message));
2183        }
2184    }
2185
2186    /**
2187     * helper, prints the milli time since boot wi and w/o suspended time
2188     */
2189    String printTime() {
2190        StringBuilder sb = new StringBuilder();
2191        sb.append(" rt=").append(mClock.getUptimeSinceBootMillis());
2192        sb.append("/").append(mClock.getElapsedSinceBootMillis());
2193        return sb.toString();
2194    }
2195
2196    /**
2197     * Return the additional string to be logged by LogRec, default
2198     *
2199     * @param msg that was processed
2200     * @return information to be logged as a String
2201     */
2202    @Override
2203    protected String getLogRecString(Message msg) {
2204        WifiConfiguration config;
2205        Long now;
2206        String report;
2207        String key;
2208        StringBuilder sb = new StringBuilder();
2209        if (mScreenOn) {
2210            sb.append("!");
2211        }
2212        if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
2213            sb.append("(").append(messageHandlingStatus).append(")");
2214        }
2215        sb.append(smToString(msg));
2216        if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
2217            sb.append(" uid=" + msg.sendingUid);
2218        }
2219        sb.append(" ").append(printTime());
2220        switch (msg.what) {
2221            case CMD_START_SCAN:
2222                now = mClock.getWallClockMillis();
2223                sb.append(" ");
2224                sb.append(Integer.toString(msg.arg1));
2225                sb.append(" ");
2226                sb.append(Integer.toString(msg.arg2));
2227                sb.append(" ic=");
2228                sb.append(Integer.toString(sScanAlarmIntentCount));
2229                if (msg.obj != null) {
2230                    Bundle bundle = (Bundle) msg.obj;
2231                    Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
2232                    if (request != 0) {
2233                        sb.append(" proc(ms):").append(now - request);
2234                    }
2235                }
2236                if (mIsScanOngoing) sb.append(" onGoing");
2237                if (mIsFullScanOngoing) sb.append(" full");
2238                sb.append(" rssi=").append(mWifiInfo.getRssi());
2239                sb.append(" f=").append(mWifiInfo.getFrequency());
2240                sb.append(" sc=").append(mWifiInfo.score);
2241                sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2242                sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2243                sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2244                sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2245                sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2246                if (lastScanFreqs != null) {
2247                    sb.append(" list=");
2248                    for(int freq : lastScanFreqs) {
2249                        sb.append(freq).append(",");
2250                    }
2251                }
2252                report = reportOnTime();
2253                if (report != null) {
2254                    sb.append(" ").append(report);
2255                }
2256                break;
2257            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2258                sb.append(" ");
2259                sb.append(Integer.toString(msg.arg1));
2260                sb.append(" ");
2261                sb.append(Integer.toString(msg.arg2));
2262                StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
2263                if (stateChangeResult != null) {
2264                    sb.append(stateChangeResult.toString());
2265                }
2266                break;
2267            case WifiManager.SAVE_NETWORK:
2268                sb.append(" ");
2269                sb.append(Integer.toString(msg.arg1));
2270                sb.append(" ");
2271                sb.append(Integer.toString(msg.arg2));
2272                config = (WifiConfiguration) msg.obj;
2273                if (config != null) {
2274                    sb.append(" ").append(config.configKey());
2275                    sb.append(" nid=").append(config.networkId);
2276                    if (config.hiddenSSID) {
2277                        sb.append(" hidden");
2278                    }
2279                    if (config.preSharedKey != null
2280                            && !config.preSharedKey.equals("*")) {
2281                        sb.append(" hasPSK");
2282                    }
2283                    if (config.ephemeral) {
2284                        sb.append(" ephemeral");
2285                    }
2286                    if (config.selfAdded) {
2287                        sb.append(" selfAdded");
2288                    }
2289                    sb.append(" cuid=").append(config.creatorUid);
2290                    sb.append(" suid=").append(config.lastUpdateUid);
2291                }
2292                break;
2293            case WifiManager.FORGET_NETWORK:
2294                sb.append(" ");
2295                sb.append(Integer.toString(msg.arg1));
2296                sb.append(" ");
2297                sb.append(Integer.toString(msg.arg2));
2298                config = (WifiConfiguration) msg.obj;
2299                if (config != null) {
2300                    sb.append(" ").append(config.configKey());
2301                    sb.append(" nid=").append(config.networkId);
2302                    if (config.hiddenSSID) {
2303                        sb.append(" hidden");
2304                    }
2305                    if (config.preSharedKey != null) {
2306                        sb.append(" hasPSK");
2307                    }
2308                    if (config.ephemeral) {
2309                        sb.append(" ephemeral");
2310                    }
2311                    if (config.selfAdded) {
2312                        sb.append(" selfAdded");
2313                    }
2314                    sb.append(" cuid=").append(config.creatorUid);
2315                    sb.append(" suid=").append(config.lastUpdateUid);
2316                    WifiConfiguration.NetworkSelectionStatus netWorkSelectionStatus =
2317                            config.getNetworkSelectionStatus();
2318                    sb.append(" ajst=").append(
2319                            netWorkSelectionStatus.getNetworkStatusString());
2320                }
2321                break;
2322            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2323                sb.append(" ");
2324                sb.append(Integer.toString(msg.arg1));
2325                sb.append(" ");
2326                sb.append(Integer.toString(msg.arg2));
2327                String bssid = (String) msg.obj;
2328                if (bssid != null && bssid.length() > 0) {
2329                    sb.append(" ");
2330                    sb.append(bssid);
2331                }
2332                sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
2333                break;
2334            case WifiMonitor.SCAN_RESULTS_EVENT:
2335                sb.append(" ");
2336                sb.append(Integer.toString(msg.arg1));
2337                sb.append(" ");
2338                sb.append(Integer.toString(msg.arg2));
2339                if (mScanResults != null) {
2340                    sb.append(" found=");
2341                    sb.append(mScanResults.size());
2342                }
2343                sb.append(" known=").append(mNumScanResultsKnown);
2344                sb.append(" got=").append(mNumScanResultsReturned);
2345                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2346                sb.append(String.format(" con=%d", mConnectionReqCount));
2347                sb.append(String.format(" untrustedcn=%d", mUntrustedReqCount));
2348                key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2349                if (key != null) {
2350                    sb.append(" last=").append(key);
2351                }
2352                break;
2353            case WifiMonitor.SCAN_FAILED_EVENT:
2354                break;
2355            case WifiMonitor.NETWORK_CONNECTION_EVENT:
2356                sb.append(" ");
2357                sb.append(Integer.toString(msg.arg1));
2358                sb.append(" ");
2359                sb.append(Integer.toString(msg.arg2));
2360                sb.append(" ").append(mLastBssid);
2361                sb.append(" nid=").append(mLastNetworkId);
2362                config = getCurrentWifiConfiguration();
2363                if (config != null) {
2364                    sb.append(" ").append(config.configKey());
2365                }
2366                key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2367                if (key != null) {
2368                    sb.append(" last=").append(key);
2369                }
2370                break;
2371            case CMD_TARGET_BSSID:
2372            case CMD_ASSOCIATED_BSSID:
2373                sb.append(" ");
2374                sb.append(Integer.toString(msg.arg1));
2375                sb.append(" ");
2376                sb.append(Integer.toString(msg.arg2));
2377                if (msg.obj != null) {
2378                    sb.append(" BSSID=").append((String) msg.obj);
2379                }
2380                if (mTargetRoamBSSID != null) {
2381                    sb.append(" Target=").append(mTargetRoamBSSID);
2382                }
2383                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
2384                break;
2385            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2386                if (msg.obj != null) {
2387                    sb.append(" ").append((String) msg.obj);
2388                }
2389                sb.append(" nid=").append(msg.arg1);
2390                sb.append(" reason=").append(msg.arg2);
2391                if (mLastBssid != null) {
2392                    sb.append(" lastbssid=").append(mLastBssid);
2393                }
2394                if (mWifiInfo.getFrequency() != -1) {
2395                    sb.append(" freq=").append(mWifiInfo.getFrequency());
2396                    sb.append(" rssi=").append(mWifiInfo.getRssi());
2397                }
2398                if (isLinkDebouncing()) {
2399                    sb.append(" debounce");
2400                }
2401                break;
2402            case WifiMonitor.SSID_TEMP_DISABLED:
2403            case WifiMonitor.SSID_REENABLED:
2404                sb.append(" nid=").append(msg.arg1);
2405                if (msg.obj != null) {
2406                    sb.append(" ").append((String) msg.obj);
2407                }
2408                config = getCurrentWifiConfiguration();
2409                if (config != null) {
2410                    WifiConfiguration.NetworkSelectionStatus netWorkSelectionStatus =
2411                            config.getNetworkSelectionStatus();
2412                    sb.append(" cur=").append(config.configKey());
2413                    sb.append(" ajst=").append(netWorkSelectionStatus.getNetworkStatusString());
2414                    if (config.selfAdded) {
2415                        sb.append(" selfAdded");
2416                    }
2417                    if (config.status != 0) {
2418                        sb.append(" st=").append(config.status);
2419                        sb.append(" rs=").append(
2420                                netWorkSelectionStatus.getNetworkDisableReasonString());
2421                    }
2422                    if (config.lastConnected != 0) {
2423                        now = mClock.getWallClockMillis();
2424                        sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)");
2425                    }
2426                    if (mLastBssid != null) {
2427                        sb.append(" lastbssid=").append(mLastBssid);
2428                    }
2429                    if (mWifiInfo.getFrequency() != -1) {
2430                        sb.append(" freq=").append(mWifiInfo.getFrequency());
2431                        sb.append(" rssi=").append(mWifiInfo.getRssi());
2432                        sb.append(" bssid=").append(mWifiInfo.getBSSID());
2433                    }
2434                }
2435                break;
2436            case CMD_RSSI_POLL:
2437            case CMD_UNWANTED_NETWORK:
2438            case WifiManager.RSSI_PKTCNT_FETCH:
2439                sb.append(" ");
2440                sb.append(Integer.toString(msg.arg1));
2441                sb.append(" ");
2442                sb.append(Integer.toString(msg.arg2));
2443                if (mWifiInfo.getSSID() != null)
2444                    if (mWifiInfo.getSSID() != null)
2445                        sb.append(" ").append(mWifiInfo.getSSID());
2446                if (mWifiInfo.getBSSID() != null)
2447                    sb.append(" ").append(mWifiInfo.getBSSID());
2448                sb.append(" rssi=").append(mWifiInfo.getRssi());
2449                sb.append(" f=").append(mWifiInfo.getFrequency());
2450                sb.append(" sc=").append(mWifiInfo.score);
2451                sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2452                sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2453                sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2454                sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2455                sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2456                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2457                report = reportOnTime();
2458                if (report != null) {
2459                    sb.append(" ").append(report);
2460                }
2461                if (mWifiScoreReport.isLastReportValid()) {
2462                    sb.append(mWifiScoreReport.getLastReport());
2463                }
2464                break;
2465            case CMD_START_CONNECT:
2466            case WifiManager.CONNECT_NETWORK:
2467                sb.append(" ");
2468                sb.append(Integer.toString(msg.arg1));
2469                sb.append(" ");
2470                sb.append(Integer.toString(msg.arg2));
2471                config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2472                if (config != null) {
2473                    sb.append(" ").append(config.configKey());
2474                    if (config.visibility != null) {
2475                        sb.append(" ").append(config.visibility.toString());
2476                    }
2477                }
2478                if (mTargetRoamBSSID != null) {
2479                    sb.append(" ").append(mTargetRoamBSSID);
2480                }
2481                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
2482                config = getCurrentWifiConfiguration();
2483                if (config != null) {
2484                    sb.append(config.configKey());
2485                    if (config.visibility != null) {
2486                        sb.append(" ").append(config.visibility.toString());
2487                    }
2488                }
2489                break;
2490            case CMD_START_ROAM:
2491                sb.append(" ");
2492                sb.append(Integer.toString(msg.arg1));
2493                sb.append(" ");
2494                sb.append(Integer.toString(msg.arg2));
2495                ScanResult result = (ScanResult) msg.obj;
2496                if (result != null) {
2497                    now = mClock.getWallClockMillis();
2498                    sb.append(" bssid=").append(result.BSSID);
2499                    sb.append(" rssi=").append(result.level);
2500                    sb.append(" freq=").append(result.frequency);
2501                    if (result.seen > 0 && result.seen < now) {
2502                        sb.append(" seen=").append(now - result.seen);
2503                    } else {
2504                        // Somehow the timestamp for this scan result is inconsistent
2505                        sb.append(" !seen=").append(result.seen);
2506                    }
2507                }
2508                if (mTargetRoamBSSID != null) {
2509                    sb.append(" ").append(mTargetRoamBSSID);
2510                }
2511                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
2512                sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
2513                break;
2514            case CMD_ADD_OR_UPDATE_NETWORK:
2515                sb.append(" ");
2516                sb.append(Integer.toString(msg.arg1));
2517                sb.append(" ");
2518                sb.append(Integer.toString(msg.arg2));
2519                if (msg.obj != null) {
2520                    config = (WifiConfiguration) msg.obj;
2521                    sb.append(" ").append(config.configKey());
2522                    sb.append(" prio=").append(config.priority);
2523                    sb.append(" status=").append(config.status);
2524                    if (config.BSSID != null) {
2525                        sb.append(" ").append(config.BSSID);
2526                    }
2527                    WifiConfiguration curConfig = getCurrentWifiConfiguration();
2528                    if (curConfig != null) {
2529                        if (curConfig.configKey().equals(config.configKey())) {
2530                            sb.append(" is current");
2531                        } else {
2532                            sb.append(" current=").append(curConfig.configKey());
2533                            sb.append(" prio=").append(curConfig.priority);
2534                            sb.append(" status=").append(curConfig.status);
2535                        }
2536                    }
2537                }
2538                break;
2539            case WifiManager.DISABLE_NETWORK:
2540            case CMD_ENABLE_NETWORK:
2541                sb.append(" ");
2542                sb.append(Integer.toString(msg.arg1));
2543                sb.append(" ");
2544                sb.append(Integer.toString(msg.arg2));
2545                key = mWifiConfigManager.getLastSelectedNetworkConfigKey();
2546                if (key != null) {
2547                    sb.append(" last=").append(key);
2548                }
2549                config = mWifiConfigManager.getConfiguredNetwork(msg.arg1);
2550                if (config != null && (key == null || !config.configKey().equals(key))) {
2551                    sb.append(" target=").append(key);
2552                }
2553                break;
2554            case CMD_GET_CONFIGURED_NETWORKS:
2555                sb.append(" ");
2556                sb.append(Integer.toString(msg.arg1));
2557                sb.append(" ");
2558                sb.append(Integer.toString(msg.arg2));
2559                sb.append(" num=").append(mWifiConfigManager.getConfiguredNetworks().size());
2560                break;
2561            case DhcpClient.CMD_PRE_DHCP_ACTION:
2562                sb.append(" ");
2563                sb.append(Integer.toString(msg.arg1));
2564                sb.append(" ");
2565                sb.append(Integer.toString(msg.arg2));
2566                sb.append(" txpkts=").append(mWifiInfo.txSuccess);
2567                sb.append(",").append(mWifiInfo.txBad);
2568                sb.append(",").append(mWifiInfo.txRetries);
2569                break;
2570            case DhcpClient.CMD_POST_DHCP_ACTION:
2571                sb.append(" ");
2572                sb.append(Integer.toString(msg.arg1));
2573                sb.append(" ");
2574                sb.append(Integer.toString(msg.arg2));
2575                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
2576                    sb.append(" OK ");
2577                } else if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
2578                    sb.append(" FAIL ");
2579                }
2580                if (mLinkProperties != null) {
2581                    sb.append(" ");
2582                    sb.append(getLinkPropertiesSummary(mLinkProperties));
2583                }
2584                break;
2585            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
2586                sb.append(" ");
2587                sb.append(Integer.toString(msg.arg1));
2588                sb.append(" ");
2589                sb.append(Integer.toString(msg.arg2));
2590                if (msg.obj != null) {
2591                    NetworkInfo info = (NetworkInfo) msg.obj;
2592                    NetworkInfo.State state = info.getState();
2593                    NetworkInfo.DetailedState detailedState = info.getDetailedState();
2594                    if (state != null) {
2595                        sb.append(" st=").append(state);
2596                    }
2597                    if (detailedState != null) {
2598                        sb.append("/").append(detailedState);
2599                    }
2600                }
2601                break;
2602            case CMD_IP_CONFIGURATION_LOST:
2603                int count = -1;
2604                WifiConfiguration c = getCurrentWifiConfiguration();
2605                if (c != null) {
2606                    count = c.getNetworkSelectionStatus().getDisableReasonCounter(
2607                            WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
2608                }
2609                sb.append(" ");
2610                sb.append(Integer.toString(msg.arg1));
2611                sb.append(" ");
2612                sb.append(Integer.toString(msg.arg2));
2613                sb.append(" failures: ");
2614                sb.append(Integer.toString(count));
2615                sb.append("/");
2616                sb.append(Integer.toString(mFacade.getIntegerSetting(
2617                        mContext, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 0)));
2618                if (mWifiInfo.getBSSID() != null) {
2619                    sb.append(" ").append(mWifiInfo.getBSSID());
2620                }
2621                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2622                break;
2623            case CMD_UPDATE_LINKPROPERTIES:
2624                sb.append(" ");
2625                sb.append(Integer.toString(msg.arg1));
2626                sb.append(" ");
2627                sb.append(Integer.toString(msg.arg2));
2628                if (mLinkProperties != null) {
2629                    sb.append(" ");
2630                    sb.append(getLinkPropertiesSummary(mLinkProperties));
2631                }
2632                break;
2633            case CMD_IP_REACHABILITY_LOST:
2634                if (msg.obj != null) {
2635                    sb.append(" ").append((String) msg.obj);
2636                }
2637                break;
2638            case CMD_INSTALL_PACKET_FILTER:
2639                sb.append(" len=" + ((byte[])msg.obj).length);
2640                break;
2641            case CMD_SET_FALLBACK_PACKET_FILTERING:
2642                sb.append(" enabled=" + (boolean)msg.obj);
2643                break;
2644            case CMD_ROAM_WATCHDOG_TIMER:
2645                sb.append(" ");
2646                sb.append(Integer.toString(msg.arg1));
2647                sb.append(" ");
2648                sb.append(Integer.toString(msg.arg2));
2649                sb.append(" cur=").append(roamWatchdogCount);
2650                break;
2651            case CMD_DISCONNECTING_WATCHDOG_TIMER:
2652                sb.append(" ");
2653                sb.append(Integer.toString(msg.arg1));
2654                sb.append(" ");
2655                sb.append(Integer.toString(msg.arg2));
2656                sb.append(" cur=").append(disconnectingWatchdogCount);
2657                break;
2658            case CMD_START_RSSI_MONITORING_OFFLOAD:
2659            case CMD_STOP_RSSI_MONITORING_OFFLOAD:
2660            case CMD_RSSI_THRESHOLD_BREACH:
2661                sb.append(" rssi=");
2662                sb.append(Integer.toString(msg.arg1));
2663                sb.append(" thresholds=");
2664                sb.append(Arrays.toString(mRssiRanges));
2665                break;
2666            case CMD_USER_SWITCH:
2667                sb.append(" userId=");
2668                sb.append(Integer.toString(msg.arg1));
2669                break;
2670            case CMD_IPV4_PROVISIONING_SUCCESS:
2671                sb.append(" ");
2672                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
2673                    sb.append("DHCP_OK");
2674                } else if (msg.arg1 == CMD_STATIC_IP_SUCCESS) {
2675                    sb.append("STATIC_OK");
2676                } else {
2677                    sb.append(Integer.toString(msg.arg1));
2678                }
2679                break;
2680            case CMD_IPV4_PROVISIONING_FAILURE:
2681                sb.append(" ");
2682                if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
2683                    sb.append("DHCP_FAIL");
2684                } else if (msg.arg1 == CMD_STATIC_IP_FAILURE) {
2685                    sb.append("STATIC_FAIL");
2686                } else {
2687                    sb.append(Integer.toString(msg.arg1));
2688                }
2689                break;
2690            default:
2691                sb.append(" ");
2692                sb.append(Integer.toString(msg.arg1));
2693                sb.append(" ");
2694                sb.append(Integer.toString(msg.arg2));
2695                break;
2696        }
2697
2698        return sb.toString();
2699    }
2700
2701    private void handleScreenStateChanged(boolean screenOn) {
2702        mScreenOn = screenOn;
2703        if (mVerboseLoggingEnabled) {
2704            logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
2705                    + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
2706                    + " state " + getCurrentState().getName()
2707                    + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
2708        }
2709        enableRssiPolling(screenOn);
2710        if (mUserWantsSuspendOpt.get()) {
2711            int shouldReleaseWakeLock = 0;
2712            if (screenOn) {
2713                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, shouldReleaseWakeLock);
2714            } else {
2715                if (isConnected()) {
2716                    // Allow 2s for suspend optimizations to be set
2717                    mSuspendWakeLock.acquire(2000);
2718                    shouldReleaseWakeLock = 1;
2719                }
2720                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, shouldReleaseWakeLock);
2721            }
2722        }
2723
2724        getWifiLinkLayerStats();
2725        mOnTimeScreenStateChange = mOnTime;
2726        lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
2727
2728        mWifiMetrics.setScreenState(screenOn);
2729
2730        if (mWifiConnectivityManager != null) {
2731            mWifiConnectivityManager.handleScreenStateChanged(screenOn);
2732        }
2733
2734        if (mVerboseLoggingEnabled) log("handleScreenStateChanged Exit: " + screenOn);
2735    }
2736
2737    private void checkAndSetConnectivityInstance() {
2738        if (mCm == null) {
2739            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
2740        }
2741    }
2742
2743    private void setSuspendOptimizationsNative(int reason, boolean enabled) {
2744        if (mVerboseLoggingEnabled) {
2745            log("setSuspendOptimizationsNative: " + reason + " " + enabled
2746                    + " -want " + mUserWantsSuspendOpt.get()
2747                    + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2748                    + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2749                    + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2750                    + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2751        }
2752        //mWifiNative.setSuspendOptimizations(enabled);
2753
2754        if (enabled) {
2755            mSuspendOptNeedsDisabled &= ~reason;
2756            /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
2757            if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
2758                if (mVerboseLoggingEnabled) {
2759                    log("setSuspendOptimizationsNative do it " + reason + " " + enabled
2760                            + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
2761                            + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
2762                            + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
2763                            + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
2764                }
2765                mWifiNative.setSuspendOptimizations(true);
2766            }
2767        } else {
2768            mSuspendOptNeedsDisabled |= reason;
2769            mWifiNative.setSuspendOptimizations(false);
2770        }
2771    }
2772
2773    private void setSuspendOptimizations(int reason, boolean enabled) {
2774        if (mVerboseLoggingEnabled) log("setSuspendOptimizations: " + reason + " " + enabled);
2775        if (enabled) {
2776            mSuspendOptNeedsDisabled &= ~reason;
2777        } else {
2778            mSuspendOptNeedsDisabled |= reason;
2779        }
2780        if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2781    }
2782
2783    private void setWifiState(int wifiState) {
2784        final int previousWifiState = mWifiState.get();
2785
2786        try {
2787            if (wifiState == WIFI_STATE_ENABLED) {
2788                mBatteryStats.noteWifiOn();
2789            } else if (wifiState == WIFI_STATE_DISABLED) {
2790                mBatteryStats.noteWifiOff();
2791            }
2792        } catch (RemoteException e) {
2793            loge("Failed to note battery stats in wifi");
2794        }
2795
2796        mWifiState.set(wifiState);
2797
2798        if (mVerboseLoggingEnabled) log("setWifiState: " + syncGetWifiStateByName());
2799
2800        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
2801        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2802        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
2803        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
2804        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2805    }
2806
2807    private void setWifiApState(int wifiApState, int reason) {
2808        final int previousWifiApState = mWifiApState.get();
2809
2810        try {
2811            if (wifiApState == WIFI_AP_STATE_ENABLED) {
2812                mBatteryStats.noteWifiOn();
2813            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
2814                mBatteryStats.noteWifiOff();
2815            }
2816        } catch (RemoteException e) {
2817            loge("Failed to note battery stats in wifi");
2818        }
2819
2820        // Update state
2821        mWifiApState.set(wifiApState);
2822
2823        if (mVerboseLoggingEnabled) log("setWifiApState: " + syncGetWifiApStateByName());
2824
2825        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
2826        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2827        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
2828        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
2829        if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
2830            //only set reason number when softAP start failed
2831            intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
2832        }
2833
2834        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2835    }
2836
2837    private void setScanResults() {
2838        mNumScanResultsKnown = 0;
2839        mNumScanResultsReturned = 0;
2840
2841        ArrayList<ScanDetail> scanResults = mWifiNative.getScanResults();
2842
2843        if (scanResults.isEmpty()) {
2844            mScanResults = new ArrayList<>();
2845            return;
2846        }
2847
2848        // TODO(b/31065385): mWifiConfigManager.trimANQPCache(false);
2849
2850        boolean connected = mLastBssid != null;
2851        long activeBssid = 0L;
2852        if (connected) {
2853            try {
2854                activeBssid = Utils.parseMac(mLastBssid);
2855            } catch (IllegalArgumentException iae) {
2856                connected = false;
2857            }
2858        }
2859
2860        synchronized (mScanResultsLock) {
2861            mScanResults = scanResults;
2862            mNumScanResultsReturned = mScanResults.size();
2863        }
2864
2865        if (isLinkDebouncing()) {
2866            // If debouncing, we dont re-select a SSID or BSSID hence
2867            // there is no need to call the network selection code
2868            // in WifiAutoJoinController, instead,
2869            // just try to reconnect to the same SSID by triggering a roam
2870            // The third parameter 1 means roam not from network selection but debouncing
2871            sendMessage(CMD_START_ROAM, mLastNetworkId, 1, null);
2872        }
2873    }
2874
2875    /*
2876     * Fetch RSSI, linkspeed, and frequency on current connection
2877     */
2878    private void fetchRssiLinkSpeedAndFrequencyNative() {
2879        Integer newRssi = null;
2880        Integer newLinkSpeed = null;
2881        Integer newFrequency = null;
2882        int[] poll_result = null;
2883        try {
2884            poll_result = mClientInterface.signalPoll();
2885            if (poll_result == null || poll_result.length != 2) {
2886                return;
2887            }
2888        } catch (RemoteException e1) { }
2889
2890        newRssi = poll_result[0];
2891        newLinkSpeed = poll_result[1];
2892
2893        // Ideally we shoudn't rely on signal polls to update frequency: b/31595463.
2894        // TODO(nywang): When wificond finally takes over the scanning
2895        // function, we should cache the frequency of asscociated ap from scan results.
2896        String signalPoll = mWifiNative.signalPoll();
2897
2898        if (signalPoll != null) {
2899            String[] lines = signalPoll.split("\n");
2900            for (String line : lines) {
2901                String[] prop = line.split("=");
2902                if (prop.length < 2) continue;
2903                try {
2904                    if (prop[0].equals("FREQUENCY")) {
2905                        newFrequency = Integer.parseInt(prop[1]);
2906                    }
2907                } catch (NumberFormatException e) {
2908                    //Ignore, defaults on rssi and linkspeed are assigned
2909                }
2910            }
2911        }
2912
2913        if (mVerboseLoggingEnabled) {
2914            logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" + newRssi +
2915                 " linkspeed=" + newLinkSpeed + " freq=" + newFrequency);
2916        }
2917
2918        if (newRssi != null && newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
2919            // screen out invalid values
2920            /* some implementations avoid negative values by adding 256
2921             * so we need to adjust for that here.
2922             */
2923            if (newRssi > 0) newRssi -= 256;
2924            mWifiInfo.setRssi(newRssi);
2925            /*
2926             * Log the rssi poll value in metrics
2927             */
2928            mWifiMetrics.incrementRssiPollRssiCount(newRssi);
2929            /*
2930             * Rather then sending the raw RSSI out every time it
2931             * changes, we precalculate the signal level that would
2932             * be displayed in the status bar, and only send the
2933             * broadcast if that much more coarse-grained number
2934             * changes. This cuts down greatly on the number of
2935             * broadcasts, at the cost of not informing others
2936             * interested in RSSI of all the changes in signal
2937             * level.
2938             */
2939            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
2940            if (newSignalLevel != mLastSignalLevel) {
2941                updateCapabilities(getCurrentWifiConfiguration());
2942                sendRssiChangeBroadcast(newRssi);
2943            }
2944            mLastSignalLevel = newSignalLevel;
2945        } else {
2946            mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
2947            updateCapabilities(getCurrentWifiConfiguration());
2948        }
2949
2950        if (newLinkSpeed != null) {
2951            mWifiInfo.setLinkSpeed(newLinkSpeed);
2952        }
2953        if (newFrequency != null && newFrequency > 0) {
2954            if (ScanResult.is5GHz(newFrequency)) {
2955                mWifiConnectionStatistics.num5GhzConnected++;
2956            }
2957            if (ScanResult.is24GHz(newFrequency)) {
2958                mWifiConnectionStatistics.num24GhzConnected++;
2959            }
2960            mWifiInfo.setFrequency(newFrequency);
2961        }
2962        mWifiConfigManager.updateScanDetailCacheFromWifiInfo(mWifiInfo);
2963    }
2964
2965    // Polling has completed, hence we wont have a score anymore
2966    private void cleanWifiScore() {
2967        mWifiInfo.txBadRate = 0;
2968        mWifiInfo.txSuccessRate = 0;
2969        mWifiInfo.txRetriesRate = 0;
2970        mWifiInfo.rxSuccessRate = 0;
2971        mWifiScoreReport.reset();
2972    }
2973
2974    /**
2975     * Fetch TX packet counters on current connection
2976     */
2977    private void fetchPktcntNative(RssiPacketCountInfo info) {
2978        int[] counters = null;
2979        try {
2980            counters = mClientInterface.getPacketCounters();
2981            if (counters == null || counters.length != 2) {
2982                return;
2983            }
2984        } catch (RemoteException e1) {}
2985        info.txgood = counters[0];
2986        info.txbad = counters[1];
2987    }
2988
2989    private void updateLinkProperties(LinkProperties newLp) {
2990        if (mVerboseLoggingEnabled) {
2991            log("Link configuration changed for netId: " + mLastNetworkId
2992                    + " old: " + mLinkProperties + " new: " + newLp);
2993        }
2994        // We own this instance of LinkProperties because IpManager passes us a copy.
2995        mLinkProperties = newLp;
2996        if (mNetworkAgent != null) {
2997            mNetworkAgent.sendLinkProperties(mLinkProperties);
2998        }
2999
3000        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
3001            // If anything has changed and we're already connected, send out a notification.
3002            // TODO: Update all callers to use NetworkCallbacks and delete this.
3003            sendLinkConfigurationChangedBroadcast();
3004        }
3005
3006        if (mVerboseLoggingEnabled) {
3007            StringBuilder sb = new StringBuilder();
3008            sb.append("updateLinkProperties nid: " + mLastNetworkId);
3009            sb.append(" state: " + getNetworkDetailedState());
3010
3011            if (mLinkProperties != null) {
3012                sb.append(" ");
3013                sb.append(getLinkPropertiesSummary(mLinkProperties));
3014            }
3015            logd(sb.toString());
3016        }
3017    }
3018
3019    /**
3020     * Clears all our link properties.
3021     */
3022    private void clearLinkProperties() {
3023        // Clear the link properties obtained from DHCP. The only caller of this
3024        // function has already called IpManager#stop(), which clears its state.
3025        synchronized (mDhcpResultsLock) {
3026            if (mDhcpResults != null) {
3027                mDhcpResults.clear();
3028            }
3029        }
3030
3031        // Now clear the merged link properties.
3032        mLinkProperties.clear();
3033        if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
3034    }
3035
3036    /**
3037     * try to update default route MAC address.
3038     */
3039    private String updateDefaultRouteMacAddress(int timeout) {
3040        String address = null;
3041        for (RouteInfo route : mLinkProperties.getRoutes()) {
3042            if (route.isDefaultRoute() && route.hasGateway()) {
3043                InetAddress gateway = route.getGateway();
3044                if (gateway instanceof Inet4Address) {
3045                    if (mVerboseLoggingEnabled) {
3046                        logd("updateDefaultRouteMacAddress found Ipv4 default :"
3047                                + gateway.getHostAddress());
3048                    }
3049                    address = macAddressFromRoute(gateway.getHostAddress());
3050                    /* The gateway's MAC address is known */
3051                    if ((address == null) && (timeout > 0)) {
3052                        boolean reachable = false;
3053                        try {
3054                            reachable = gateway.isReachable(timeout);
3055                        } catch (Exception e) {
3056                            loge("updateDefaultRouteMacAddress exception reaching :"
3057                                    + gateway.getHostAddress());
3058
3059                        } finally {
3060                            if (reachable == true) {
3061
3062                                address = macAddressFromRoute(gateway.getHostAddress());
3063                                if (mVerboseLoggingEnabled) {
3064                                    logd("updateDefaultRouteMacAddress reachable (tried again) :"
3065                                            + gateway.getHostAddress() + " found " + address);
3066                                }
3067                            }
3068                        }
3069                    }
3070                    if (address != null) {
3071                        mWifiConfigManager.setNetworkDefaultGwMacAddress(mLastNetworkId, address);
3072                    }
3073                }
3074            }
3075        }
3076        return address;
3077    }
3078
3079    private void sendRssiChangeBroadcast(final int newRssi) {
3080        try {
3081            mBatteryStats.noteWifiRssiChanged(newRssi);
3082        } catch (RemoteException e) {
3083            // Won't happen.
3084        }
3085        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
3086        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3087        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
3088        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3089    }
3090
3091    private void sendNetworkStateChangeBroadcast(String bssid) {
3092        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
3093        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3094        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
3095        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
3096        if (bssid != null)
3097            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
3098        if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
3099                mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
3100            // We no longer report MAC address to third-parties and our code does
3101            // not rely on this broadcast, so just send the default MAC address.
3102            fetchRssiLinkSpeedAndFrequencyNative();
3103            WifiInfo sentWifiInfo = new WifiInfo(mWifiInfo);
3104            sentWifiInfo.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
3105            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, sentWifiInfo);
3106        }
3107        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3108    }
3109
3110    private WifiInfo getWiFiInfoForUid(int uid) {
3111        if (Binder.getCallingUid() == Process.myUid()) {
3112            return mWifiInfo;
3113        }
3114
3115        WifiInfo result = new WifiInfo(mWifiInfo);
3116        result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
3117
3118        IBinder binder = mFacade.getService("package");
3119        IPackageManager packageManager = IPackageManager.Stub.asInterface(binder);
3120
3121        try {
3122            if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
3123                    uid) == PackageManager.PERMISSION_GRANTED) {
3124                result.setMacAddress(mWifiInfo.getMacAddress());
3125            }
3126        } catch (RemoteException e) {
3127            Log.e(TAG, "Error checking receiver permission", e);
3128        }
3129
3130        return result;
3131    }
3132
3133    private void sendLinkConfigurationChangedBroadcast() {
3134        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
3135        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3136        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
3137        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
3138    }
3139
3140    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
3141        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
3142        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3143        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
3144        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
3145    }
3146
3147    /**
3148     * Record the detailed state of a network.
3149     *
3150     * @param state the new {@code DetailedState}
3151     */
3152    private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
3153        boolean hidden = false;
3154
3155        if (isLinkDebouncing() || isRoaming()) {
3156            // There is generally a confusion in the system about colluding
3157            // WiFi Layer 2 state (as reported by supplicant) and the Network state
3158            // which leads to multiple confusion.
3159            //
3160            // If link is de-bouncing or roaming, we already have an IP address
3161            // as well we were connected and are doing L2 cycles of
3162            // reconnecting or renewing IP address to check that we still have it
3163            // This L2 link flapping should ne be reflected into the Network state
3164            // which is the state of the WiFi Network visible to Layer 3 and applications
3165            // Note that once debouncing and roaming are completed, we will
3166            // set the Network state to where it should be, or leave it as unchanged
3167            //
3168            hidden = true;
3169        }
3170        if (mVerboseLoggingEnabled) {
3171            log("setDetailed state, old ="
3172                    + mNetworkInfo.getDetailedState() + " and new state=" + state
3173                    + " hidden=" + hidden);
3174        }
3175        if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null
3176                && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
3177            // Always indicate that SSID has changed
3178            if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
3179                if (mVerboseLoggingEnabled) {
3180                    log("setDetailed state send new extra info" + mWifiInfo.getSSID());
3181                }
3182                mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
3183                sendNetworkStateChangeBroadcast(null);
3184            }
3185        }
3186        if (hidden == true) {
3187            return false;
3188        }
3189
3190        if (state != mNetworkInfo.getDetailedState()) {
3191            mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
3192            if (mNetworkAgent != null) {
3193                mNetworkAgent.sendNetworkInfo(mNetworkInfo);
3194            }
3195            sendNetworkStateChangeBroadcast(null);
3196            return true;
3197        }
3198        return false;
3199    }
3200
3201    private DetailedState getNetworkDetailedState() {
3202        return mNetworkInfo.getDetailedState();
3203    }
3204
3205    private SupplicantState handleSupplicantStateChange(Message message) {
3206        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3207        SupplicantState state = stateChangeResult.state;
3208        // Supplicant state change
3209        // [31-13] Reserved for future use
3210        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
3211        // 50023 supplicant_state_changed (custom|1|5)
3212        mWifiInfo.setSupplicantState(state);
3213        // If we receive a supplicant state change with an empty SSID,
3214        // this implies that wpa_supplicant is already disconnected.
3215        // We should pretend we are still connected when linkDebouncing is on.
3216        if ((stateChangeResult.wifiSsid == null
3217                || stateChangeResult.wifiSsid.toString().isEmpty()) && isLinkDebouncing()) {
3218            return state;
3219        }
3220        // Network id is only valid when we start connecting
3221        if (SupplicantState.isConnecting(state)) {
3222            mWifiInfo.setNetworkId(lookupFrameworkNetworkId(stateChangeResult.networkId));
3223        } else {
3224            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
3225        }
3226
3227        mWifiInfo.setBSSID(stateChangeResult.BSSID);
3228
3229        mWifiInfo.setSSID(stateChangeResult.wifiSsid);
3230        WifiConfiguration config = getCurrentWifiConfiguration();
3231        if (config != null) {
3232            mWifiInfo.setEphemeral(config.ephemeral);
3233            if (!mWifiInfo.getMeteredHint()) { // don't override the value if already set.
3234                mWifiInfo.setMeteredHint(config.meteredHint);
3235            }
3236        }
3237
3238        mSupplicantStateTracker.sendMessage(Message.obtain(message));
3239
3240        return state;
3241    }
3242
3243    /**
3244     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
3245     * using the interface, stopping DHCP & disabling interface
3246     */
3247    private void handleNetworkDisconnect() {
3248        if (mVerboseLoggingEnabled) {
3249            log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
3250                    + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3251                    + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3252                    + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3253                    + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3254        }
3255
3256        stopRssiMonitoringOffload();
3257
3258        clearTargetBssid("handleNetworkDisconnect");
3259
3260        stopIpManager();
3261
3262        /* Reset data structures */
3263        mWifiScoreReport.reset();
3264        mWifiInfo.reset();
3265        mIsLinkDebouncing = false;
3266        /* Reset roaming parameters */
3267        mAutoRoaming = false;
3268
3269        setNetworkDetailedState(DetailedState.DISCONNECTED);
3270        if (mNetworkAgent != null) {
3271            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
3272            mNetworkAgent = null;
3273        }
3274
3275        /* Clear network properties */
3276        clearLinkProperties();
3277
3278        /* Cend event to CM & network change broadcast */
3279        sendNetworkStateChangeBroadcast(mLastBssid);
3280
3281        mLastBssid = null;
3282        registerDisconnected();
3283        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
3284    }
3285
3286    private void handleSupplicantConnectionLoss(boolean killSupplicant) {
3287        /* Socket connection can be lost when we do a graceful shutdown
3288        * or when the driver is hung. Ensure supplicant is stopped here.
3289        */
3290        if (killSupplicant) {
3291            mWifiMonitor.stopAllMonitoring();
3292            try {
3293                if (!mClientInterface.disableSupplicant()) {
3294                    loge("Failed to disable supplicant after connection loss");
3295                }
3296            } catch (RemoteException e) {
3297                // Remote interface has died, there is no cleanup we can do.
3298            }
3299        }
3300        mWifiNative.closeSupplicantConnection();
3301        sendSupplicantConnectionChangedBroadcast(false);
3302        setWifiState(WIFI_STATE_DISABLED);
3303    }
3304
3305    void handlePreDhcpSetup() {
3306        if (!mBluetoothConnectionActive) {
3307            /*
3308             * There are problems setting the Wi-Fi driver's power
3309             * mode to active when bluetooth coexistence mode is
3310             * enabled or sense.
3311             * <p>
3312             * We set Wi-Fi to active mode when
3313             * obtaining an IP address because we've found
3314             * compatibility issues with some routers with low power
3315             * mode.
3316             * <p>
3317             * In order for this active power mode to properly be set,
3318             * we disable coexistence mode until we're done with
3319             * obtaining an IP address.  One exception is if we
3320             * are currently connected to a headset, since disabling
3321             * coexistence would interrupt that connection.
3322             */
3323            // Disable the coexistence mode
3324            mWifiNative.setBluetoothCoexistenceMode(
3325                    WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
3326        }
3327
3328        // Disable power save and suspend optimizations during DHCP
3329        // Note: The order here is important for now. Brcm driver changes
3330        // power settings when we control suspend mode optimizations.
3331        // TODO: Remove this comment when the driver is fixed.
3332        setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
3333        mWifiNative.setPowerSave(false);
3334
3335        // Update link layer stats
3336        getWifiLinkLayerStats();
3337
3338        if (mWifiP2pChannel != null) {
3339            /* P2p discovery breaks dhcp, shut it down in order to get through this */
3340            Message msg = new Message();
3341            msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
3342            msg.arg1 = WifiP2pServiceImpl.ENABLED;
3343            msg.arg2 = DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE;
3344            msg.obj = WifiStateMachine.this;
3345            mWifiP2pChannel.sendMessage(msg);
3346        } else {
3347            // If the p2p service is not running, we can proceed directly.
3348            sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
3349        }
3350    }
3351
3352    void handlePostDhcpSetup() {
3353        /* Restore power save and suspend optimizations */
3354        setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
3355        mWifiNative.setPowerSave(true);
3356
3357        p2pSendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
3358
3359        // Set the coexistence mode back to its default value
3360        mWifiNative.setBluetoothCoexistenceMode(
3361                WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
3362    }
3363
3364    /**
3365     * Inform other components (WifiMetrics, WifiDiagnostics, etc.) that the current connection attempt
3366     * has concluded.
3367     */
3368    private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode) {
3369        mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode);
3370        switch (level2FailureCode) {
3371            case WifiMetrics.ConnectionEvent.FAILURE_NONE:
3372            case WifiMetrics.ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
3373            case WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED:
3374                // WifiDiagnostics doesn't care about success, or pre-empted connections.
3375                break;
3376            default:
3377                mWifiDiagnostics.reportConnectionFailure();
3378        }
3379    }
3380
3381    private void handleIPv4Success(DhcpResults dhcpResults) {
3382        if (mVerboseLoggingEnabled) {
3383            logd("handleIPv4Success <" + dhcpResults.toString() + ">");
3384            logd("link address " + dhcpResults.ipAddress);
3385        }
3386
3387        Inet4Address addr;
3388        synchronized (mDhcpResultsLock) {
3389            mDhcpResults = dhcpResults;
3390            addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
3391        }
3392
3393        if (isRoaming()) {
3394            int previousAddress = mWifiInfo.getIpAddress();
3395            int newAddress = NetworkUtils.inetAddressToInt(addr);
3396            if (previousAddress != newAddress) {
3397                logd("handleIPv4Success, roaming and address changed" +
3398                        mWifiInfo + " got: " + addr);
3399            }
3400        }
3401        mWifiInfo.setInetAddress(addr);
3402        if (!mWifiInfo.getMeteredHint()) { // don't override the value if already set.
3403            mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
3404            updateCapabilities(getCurrentWifiConfiguration());
3405        }
3406    }
3407
3408    private void handleSuccessfulIpConfiguration() {
3409        mLastSignalLevel = -1; // Force update of signal strength
3410        WifiConfiguration c = getCurrentWifiConfiguration();
3411        if (c != null) {
3412            // Reset IP failure tracking
3413            c.getNetworkSelectionStatus().clearDisableReasonCounter(
3414                    WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3415
3416            // Tell the framework whether the newly connected network is trusted or untrusted.
3417            updateCapabilities(c);
3418        }
3419        if (c != null) {
3420            ScanResult result = getCurrentScanResult();
3421            if (result == null) {
3422                logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
3423                        c.configKey());
3424            } else {
3425                // Clear the per BSSID failure count
3426                result.numIpConfigFailures = 0;
3427            }
3428        }
3429    }
3430
3431    private void handleIPv4Failure() {
3432        // TODO: Move this to provisioning failure, not DHCP failure.
3433        // DHCPv4 failure is expected on an IPv6-only network.
3434        mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_DHCP_FAILURE);
3435        if (mVerboseLoggingEnabled) {
3436            int count = -1;
3437            WifiConfiguration config = getCurrentWifiConfiguration();
3438            if (config != null) {
3439                count = config.getNetworkSelectionStatus().getDisableReasonCounter(
3440                        WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3441            }
3442            log("DHCP failure count=" + count);
3443        }
3444        reportConnectionAttemptEnd(
3445                WifiMetrics.ConnectionEvent.FAILURE_DHCP,
3446                WifiMetricsProto.ConnectionEvent.HLF_DHCP);
3447        synchronized(mDhcpResultsLock) {
3448             if (mDhcpResults != null) {
3449                 mDhcpResults.clear();
3450             }
3451        }
3452        if (mVerboseLoggingEnabled) {
3453            logd("handleIPv4Failure");
3454        }
3455    }
3456
3457    private void handleIpConfigurationLost() {
3458        mWifiInfo.setInetAddress(null);
3459        mWifiInfo.setMeteredHint(false);
3460
3461        mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
3462                WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3463
3464        /* DHCP times out after about 30 seconds, we do a
3465         * disconnect thru supplicant, we will let autojoin retry connecting to the network
3466         */
3467        mWifiNative.disconnect();
3468    }
3469
3470    // TODO: De-duplicated this and handleIpConfigurationLost().
3471    private void handleIpReachabilityLost() {
3472        mWifiInfo.setInetAddress(null);
3473        mWifiInfo.setMeteredHint(false);
3474
3475        // TODO: Determine whether to call some form of mWifiConfigManager.handleSSIDStateChange().
3476
3477        // Disconnect via supplicant, and let autojoin retry connecting to the network.
3478        mWifiNative.disconnect();
3479    }
3480
3481    private static IClientInterface setupDriverForClientMode(IWificond wificond) {
3482        if (wificond == null) {
3483            Log.e(TAG, "Failed to get reference to wificond");
3484            return null;
3485        }
3486
3487        IClientInterface clientInterface = null;
3488        try {
3489            clientInterface = wificond.createClientInterface();
3490        } catch (RemoteException e1) { }
3491
3492        if (clientInterface == null) {
3493            Log.e(TAG, "Could not get IClientInterface instance from wificond");
3494            return null;
3495        }
3496
3497        return clientInterface;
3498    }
3499
3500    private IApInterface setupDriverForSoftAp() {
3501        if (mWificond == null) {
3502            Log.e(TAG, "Failed to get reference to wificond");
3503            return null;
3504        }
3505
3506        IApInterface apInterface = null;
3507        try {
3508            apInterface = mWificond.createApInterface();
3509        } catch (RemoteException e1) { }
3510
3511        if (apInterface == null) {
3512            Log.e(TAG, "Could not get IApInterface instance from wificond");
3513            return null;
3514        }
3515
3516        if (!mWifiNative.startHal()) {
3517            //  starting HAL is optional
3518            Log.e(TAG, "Failed to start HAL for AP mode");
3519        }
3520        return apInterface;
3521    }
3522
3523    private byte[] macAddressFromString(String macString) {
3524        String[] macBytes = macString.split(":");
3525        if (macBytes.length != 6) {
3526            throw new IllegalArgumentException("MAC address should be 6 bytes long!");
3527        }
3528        byte[] mac = new byte[6];
3529        for (int i = 0; i < macBytes.length; i++) {
3530            Integer hexVal = Integer.parseInt(macBytes[i], 16);
3531            mac[i] = hexVal.byteValue();
3532        }
3533        return mac;
3534    }
3535
3536    /*
3537     * Read a MAC address in /proc/arp/table, used by WifistateMachine
3538     * so as to record MAC address of default gateway.
3539     **/
3540    private String macAddressFromRoute(String ipAddress) {
3541        String macAddress = null;
3542        BufferedReader reader = null;
3543        try {
3544            reader = new BufferedReader(new FileReader("/proc/net/arp"));
3545
3546            // Skip over the line bearing colum titles
3547            String line = reader.readLine();
3548
3549            while ((line = reader.readLine()) != null) {
3550                String[] tokens = line.split("[ ]+");
3551                if (tokens.length < 6) {
3552                    continue;
3553                }
3554
3555                // ARP column format is
3556                // Address HWType HWAddress Flags Mask IFace
3557                String ip = tokens[0];
3558                String mac = tokens[3];
3559
3560                if (ipAddress.equals(ip)) {
3561                    macAddress = mac;
3562                    break;
3563                }
3564            }
3565
3566            if (macAddress == null) {
3567                loge("Did not find remoteAddress {" + ipAddress + "} in " +
3568                        "/proc/net/arp");
3569            }
3570
3571        } catch (FileNotFoundException e) {
3572            loge("Could not open /proc/net/arp to lookup mac address");
3573        } catch (IOException e) {
3574            loge("Could not read /proc/net/arp to lookup mac address");
3575        } finally {
3576            try {
3577                if (reader != null) {
3578                    reader.close();
3579                }
3580            } catch (IOException e) {
3581                // Do nothing
3582            }
3583        }
3584        return macAddress;
3585
3586    }
3587
3588    private class WifiNetworkFactory extends NetworkFactory {
3589        public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
3590            super(l, c, TAG, f);
3591        }
3592
3593        @Override
3594        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
3595            synchronized (mWifiReqCountLock) {
3596                if (++mConnectionReqCount == 1) {
3597                    if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
3598                        mWifiConnectivityManager.enable(true);
3599                    }
3600                }
3601            }
3602        }
3603
3604        @Override
3605        protected void releaseNetworkFor(NetworkRequest networkRequest) {
3606            synchronized (mWifiReqCountLock) {
3607                if (--mConnectionReqCount == 0) {
3608                    if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
3609                        mWifiConnectivityManager.enable(false);
3610                    }
3611                }
3612            }
3613        }
3614
3615        @Override
3616        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3617            pw.println("mConnectionReqCount " + mConnectionReqCount);
3618        }
3619
3620    }
3621
3622    private class UntrustedWifiNetworkFactory extends NetworkFactory {
3623        public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
3624            super(l, c, tag, f);
3625        }
3626
3627        @Override
3628        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
3629            if (!networkRequest.networkCapabilities.hasCapability(
3630                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
3631                synchronized (mWifiReqCountLock) {
3632                    if (++mUntrustedReqCount == 1) {
3633                        if (mWifiConnectivityManager != null) {
3634                            if (mConnectionReqCount == 0) {
3635                                mWifiConnectivityManager.enable(true);
3636                            }
3637                            mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
3638                        }
3639                    }
3640                }
3641            }
3642        }
3643
3644        @Override
3645        protected void releaseNetworkFor(NetworkRequest networkRequest) {
3646            if (!networkRequest.networkCapabilities.hasCapability(
3647                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
3648                synchronized (mWifiReqCountLock) {
3649                    if (--mUntrustedReqCount == 0) {
3650                        if (mWifiConnectivityManager != null) {
3651                            mWifiConnectivityManager.setUntrustedConnectionAllowed(false);
3652                            if (mConnectionReqCount == 0) {
3653                                mWifiConnectivityManager.enable(false);
3654                            }
3655                        }
3656                    }
3657                }
3658            }
3659        }
3660
3661        @Override
3662        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3663            pw.println("mUntrustedReqCount " + mUntrustedReqCount);
3664        }
3665    }
3666
3667    void maybeRegisterNetworkFactory() {
3668        if (mNetworkFactory == null) {
3669            checkAndSetConnectivityInstance();
3670            if (mCm != null) {
3671                mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
3672                        NETWORKTYPE, mNetworkCapabilitiesFilter);
3673                mNetworkFactory.setScoreFilter(60);
3674                mNetworkFactory.register();
3675
3676                // We can't filter untrusted network in the capabilities filter because a trusted
3677                // network would still satisfy a request that accepts untrusted ones.
3678                mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(),
3679                        mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter);
3680                mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE);
3681                mUntrustedNetworkFactory.register();
3682            }
3683        }
3684    }
3685
3686    /********************************************************
3687     * HSM states
3688     *******************************************************/
3689
3690    class DefaultState extends State {
3691
3692        @Override
3693        public boolean processMessage(Message message) {
3694            logStateAndMessage(message, this);
3695
3696            switch (message.what) {
3697                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
3698                    AsyncChannel ac = (AsyncChannel) message.obj;
3699                    if (ac == mWifiP2pChannel) {
3700                        if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3701                            p2pSendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3702                        } else {
3703                            loge("WifiP2pService connection failure, error=" + message.arg1);
3704                        }
3705                    } else {
3706                        loge("got HALF_CONNECTED for unknown channel");
3707                    }
3708                    break;
3709                }
3710                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
3711                    AsyncChannel ac = (AsyncChannel) message.obj;
3712                    if (ac == mWifiP2pChannel) {
3713                        loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
3714                        //TODO: Re-establish connection to state machine after a delay
3715                        // mWifiP2pChannel.connect(mContext, getHandler(),
3716                        // mWifiP2pManager.getMessenger());
3717                    }
3718                    break;
3719                }
3720                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
3721                    mBluetoothConnectionActive = (message.arg1 !=
3722                            BluetoothAdapter.STATE_DISCONNECTED);
3723                    break;
3724                    /* Synchronous call returns */
3725                case CMD_PING_SUPPLICANT:
3726                case CMD_ENABLE_NETWORK:
3727                case CMD_ADD_OR_UPDATE_NETWORK:
3728                case CMD_REMOVE_NETWORK:
3729                case CMD_SAVE_CONFIG:
3730                    replyToMessage(message, message.what, FAILURE);
3731                    break;
3732                case CMD_GET_CONFIGURED_NETWORKS:
3733                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
3734                    break;
3735                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
3736                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
3737                    break;
3738                case CMD_ENABLE_RSSI_POLL:
3739                    mEnableRssiPolling = (message.arg1 == 1);
3740                    break;
3741                case CMD_SET_HIGH_PERF_MODE:
3742                    if (message.arg1 == 1) {
3743                        setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
3744                    } else {
3745                        setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
3746                    }
3747                    break;
3748                case CMD_BOOT_COMPLETED:
3749                    maybeRegisterNetworkFactory();
3750                    break;
3751                case CMD_SCREEN_STATE_CHANGED:
3752                    handleScreenStateChanged(message.arg1 != 0);
3753                    break;
3754                    /* Discard */
3755                case CMD_START_SCAN:
3756                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3757                    break;
3758                case CMD_START_SUPPLICANT:
3759                case CMD_STOP_SUPPLICANT:
3760                case CMD_STOP_SUPPLICANT_FAILED:
3761                case CMD_DRIVER_START_TIMED_OUT:
3762                case CMD_START_AP:
3763                case CMD_START_AP_FAILURE:
3764                case CMD_STOP_AP:
3765                case CMD_AP_STOPPED:
3766                case CMD_DISCONNECT:
3767                case CMD_RECONNECT:
3768                case CMD_REASSOCIATE:
3769                case CMD_RELOAD_TLS_AND_RECONNECT:
3770                case WifiMonitor.SUP_CONNECTION_EVENT:
3771                case WifiMonitor.SUP_DISCONNECTION_EVENT:
3772                case WifiMonitor.NETWORK_CONNECTION_EVENT:
3773                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3774                case WifiMonitor.SCAN_RESULTS_EVENT:
3775                case WifiMonitor.SCAN_FAILED_EVENT:
3776                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3777                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3778                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3779                case WifiMonitor.WPS_OVERLAP_EVENT:
3780                case CMD_SET_OPERATIONAL_MODE:
3781                case CMD_RSSI_POLL:
3782                case DhcpClient.CMD_PRE_DHCP_ACTION:
3783                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
3784                case DhcpClient.CMD_POST_DHCP_ACTION:
3785                case CMD_NO_NETWORKS_PERIODIC_SCAN:
3786                case CMD_DISABLE_P2P_RSP:
3787                case WifiMonitor.SUP_REQUEST_IDENTITY:
3788                case CMD_TEST_NETWORK_DISCONNECT:
3789                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
3790                case CMD_TARGET_BSSID:
3791                case CMD_START_CONNECT:
3792                case CMD_START_ROAM:
3793                case CMD_ASSOCIATED_BSSID:
3794                case CMD_UNWANTED_NETWORK:
3795                case CMD_DISCONNECTING_WATCHDOG_TIMER:
3796                case CMD_ROAM_WATCHDOG_TIMER:
3797                case CMD_DISABLE_EPHEMERAL_NETWORK:
3798                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3799                    break;
3800                case CMD_SET_SUSPEND_OPT_ENABLED:
3801                    if (message.arg1 == 1) {
3802                        if (message.arg2 == 1) {
3803                            mSuspendWakeLock.release();
3804                        }
3805                        setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
3806                    } else {
3807                        setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
3808                    }
3809                    break;
3810                case WifiMonitor.DRIVER_HUNG_EVENT:
3811                    setSupplicantRunning(false);
3812                    setSupplicantRunning(true);
3813                    break;
3814                case WifiManager.CONNECT_NETWORK:
3815                    replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
3816                            WifiManager.BUSY);
3817                    break;
3818                case WifiManager.FORGET_NETWORK:
3819                    replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
3820                            WifiManager.BUSY);
3821                    break;
3822                case WifiManager.SAVE_NETWORK:
3823                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
3824                    replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3825                            WifiManager.BUSY);
3826                    break;
3827                case WifiManager.START_WPS:
3828                    replyToMessage(message, WifiManager.WPS_FAILED,
3829                            WifiManager.BUSY);
3830                    break;
3831                case WifiManager.CANCEL_WPS:
3832                    replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
3833                            WifiManager.BUSY);
3834                    break;
3835                case WifiManager.DISABLE_NETWORK:
3836                    replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
3837                            WifiManager.BUSY);
3838                    break;
3839                case WifiManager.RSSI_PKTCNT_FETCH:
3840                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
3841                            WifiManager.BUSY);
3842                    break;
3843                case CMD_GET_SUPPORTED_FEATURES:
3844                    int featureSet = mWifiNative.getSupportedFeatureSet();
3845                    replyToMessage(message, message.what, featureSet);
3846                    break;
3847                case CMD_FIRMWARE_ALERT:
3848                    if (mWifiDiagnostics != null) {
3849                        byte[] buffer = (byte[])message.obj;
3850                        int alertReason = message.arg1;
3851                        mWifiDiagnostics.captureAlertData(alertReason, buffer);
3852                        mWifiMetrics.incrementAlertReasonCount(alertReason);
3853                    }
3854                    break;
3855                case CMD_GET_LINK_LAYER_STATS:
3856                    // Not supported hence reply with error message
3857                    replyToMessage(message, message.what, null);
3858                    break;
3859                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
3860                    NetworkInfo info = (NetworkInfo) message.obj;
3861                    mP2pConnected.set(info.isConnected());
3862                    break;
3863                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
3864                    mTemporarilyDisconnectWifi = (message.arg1 == 1);
3865                    replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
3866                    break;
3867                /* Link configuration (IP address, DNS, ...) changes notified via netlink */
3868                case CMD_UPDATE_LINKPROPERTIES:
3869                    updateLinkProperties((LinkProperties) message.obj);
3870                    break;
3871                case CMD_GET_MATCHING_CONFIG:
3872                    replyToMessage(message, message.what);
3873                    break;
3874                case CMD_IP_CONFIGURATION_SUCCESSFUL:
3875                case CMD_IP_CONFIGURATION_LOST:
3876                case CMD_IP_REACHABILITY_LOST:
3877                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3878                    break;
3879                case CMD_GET_CONNECTION_STATISTICS:
3880                    replyToMessage(message, message.what, mWifiConnectionStatistics);
3881                    break;
3882                case CMD_REMOVE_APP_CONFIGURATIONS:
3883                    deferMessage(message);
3884                    break;
3885                case CMD_REMOVE_USER_CONFIGURATIONS:
3886                    deferMessage(message);
3887                    break;
3888                case CMD_START_IP_PACKET_OFFLOAD:
3889                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
3890                            message.arg1,
3891                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
3892                    break;
3893                case CMD_STOP_IP_PACKET_OFFLOAD:
3894                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
3895                            message.arg1,
3896                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
3897                    break;
3898                case CMD_START_RSSI_MONITORING_OFFLOAD:
3899                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3900                    break;
3901                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
3902                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
3903                    break;
3904                case CMD_USER_SWITCH:
3905                    mWifiConfigManager.handleUserSwitch(message.arg1);
3906                    break;
3907                case CMD_USER_UNLOCK:
3908                    mWifiConfigManager.handleUserUnlock(message.arg1);
3909                    break;
3910                case CMD_USER_STOP:
3911                    mWifiConfigManager.handleUserStop(message.arg1);
3912                    break;
3913                case CMD_ADD_PASSPOINT_MO:
3914                case CMD_MODIFY_PASSPOINT_MO:
3915                case CMD_QUERY_OSU_ICON:
3916                case CMD_MATCH_PROVIDER_NETWORK:
3917                    /* reply with arg1 = 0 - it returns API failure to the calling app
3918                     * (message.what is not looked at)
3919                     */
3920                    replyToMessage(message, message.what);
3921                    break;
3922                case CMD_RESET_SIM_NETWORKS:
3923                    /* Defer this message until supplicant is started. */
3924                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
3925                    deferMessage(message);
3926                    break;
3927                case CMD_INSTALL_PACKET_FILTER:
3928                    mWifiNative.installPacketFilter((byte[]) message.obj);
3929                    break;
3930                case CMD_SET_FALLBACK_PACKET_FILTERING:
3931                    if ((boolean) message.obj) {
3932                        mWifiNative.startFilteringMulticastV4Packets();
3933                    } else {
3934                        mWifiNative.stopFilteringMulticastV4Packets();
3935                    }
3936                    break;
3937                case CMD_CLIENT_INTERFACE_BINDER_DEATH:
3938                    // We have lost contact with a client interface, which means that we cannot
3939                    // trust that the driver is up or that the interface is ready.  We are fit
3940                    // for no WiFi related work.
3941                    transitionTo(mInitialState);
3942                    break;
3943                default:
3944                    loge("Error! unhandled message" + message);
3945                    break;
3946            }
3947            return HANDLED;
3948        }
3949    }
3950
3951    class InitialState extends State {
3952
3953        private void cleanup() {
3954            // Tearing down the client interfaces below is going to stop our supplicant.
3955            mWifiMonitor.stopAllMonitoring();
3956
3957            mDeathRecipient.unlinkToDeath();
3958            if (mWificond != null) {
3959                try {
3960                    mWificond.tearDownInterfaces();
3961                } catch (RemoteException e) {
3962                    // There is very little we can do here
3963                    Log.e(TAG, "Failed to tear down interfaces via wificond");
3964                }
3965                mWificond = null;
3966            }
3967            mWifiNative.stopHal();
3968        }
3969
3970        @Override
3971        public void enter() {
3972            cleanup();
3973            if (mWifiP2pChannel == null && mWifiP2pServiceImpl != null) {
3974                mWifiP2pChannel = new AsyncChannel();
3975                mWifiP2pChannel.connect(mContext, getHandler(),
3976                    mWifiP2pServiceImpl.getP2pStateMachineMessenger());
3977            }
3978
3979            if (mWifiApConfigStore == null) {
3980                mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
3981            }
3982        }
3983        @Override
3984        public boolean processMessage(Message message) {
3985            logStateAndMessage(message, this);
3986            switch (message.what) {
3987                case CMD_START_SUPPLICANT:
3988                    // Refresh our reference to wificond.  This allows us to tolerate restarts.
3989                    mWificond = mWifiInjector.makeWificond();
3990                    mClientInterface = setupDriverForClientMode(mWificond);
3991                    if (mClientInterface == null ||
3992                            !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {
3993                        setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
3994                        cleanup();
3995                        break;
3996                    }
3997
3998                    try {
3999                        // A runtime crash or shutting down AP mode can leave
4000                        // IP addresses configured, and this affects
4001                        // connectivity when supplicant starts up.
4002                        // Ensure we have no IP addresses before a supplicant start.
4003                        mNwService.clearInterfaceAddresses(mInterfaceName);
4004
4005                        // Set privacy extensions
4006                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
4007
4008                        // IPv6 is enabled only as long as access point is connected since:
4009                        // - IPv6 addresses and routes stick around after disconnection
4010                        // - kernel is unaware when connected and fails to start IPv6 negotiation
4011                        // - kernel can start autoconfiguration when 802.1x is not complete
4012                        mNwService.disableIpv6(mInterfaceName);
4013                    } catch (RemoteException re) {
4014                        loge("Unable to change interface settings: " + re);
4015                    } catch (IllegalStateException ie) {
4016                        loge("Unable to change interface settings: " + ie);
4017                    }
4018
4019                    if (!mWifiNative.startHal()) {
4020                        // starting HAL is optional
4021                        Log.e(TAG, "Failed to start HAL for client mode");
4022                    }
4023
4024                    try {
4025                        if (!mClientInterface.enableSupplicant()) {
4026                            loge("Failed to start supplicant!");
4027                            setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
4028                            cleanup();
4029                            break;
4030                        }
4031                    } catch (RemoteException e) {
4032                        cleanup();
4033                        break;
4034                    }
4035                    setSupplicantLogLevel();
4036                    setWifiState(WIFI_STATE_ENABLING);
4037                    if (mVerboseLoggingEnabled) log("Supplicant start successful");
4038                    mWifiMonitor.startMonitoring(mInterfaceName);
4039                    transitionTo(mSupplicantStartingState);
4040                    break;
4041                case CMD_START_AP:
4042                    // Refresh our reference to wificond.  This allows us to tolerate restarts.
4043                    mWificond = mWifiInjector.makeWificond();
4044                    transitionTo(mSoftApState);
4045                    break;
4046                case CMD_SET_OPERATIONAL_MODE:
4047                    mOperationalMode = message.arg1;
4048                    if (mOperationalMode != DISABLED_MODE) {
4049                        sendMessage(CMD_START_SUPPLICANT);
4050                    }
4051                    break;
4052                default:
4053                    return NOT_HANDLED;
4054            }
4055            return HANDLED;
4056        }
4057    }
4058
4059    class SupplicantStartingState extends State {
4060        private void initializeWpsDetails() {
4061            String detail;
4062            detail = mPropertyService.get("ro.product.name", "");
4063            if (!mWifiNative.setDeviceName(detail)) {
4064                loge("Failed to set device name " +  detail);
4065            }
4066            detail = mPropertyService.get("ro.product.manufacturer", "");
4067            if (!mWifiNative.setManufacturer(detail)) {
4068                loge("Failed to set manufacturer " + detail);
4069            }
4070            detail = mPropertyService.get("ro.product.model", "");
4071            if (!mWifiNative.setModelName(detail)) {
4072                loge("Failed to set model name " + detail);
4073            }
4074            detail = mPropertyService.get("ro.product.model", "");
4075            if (!mWifiNative.setModelNumber(detail)) {
4076                loge("Failed to set model number " + detail);
4077            }
4078            detail = mPropertyService.get("ro.serialno", "");
4079            if (!mWifiNative.setSerialNumber(detail)) {
4080                loge("Failed to set serial number " + detail);
4081            }
4082            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
4083                loge("Failed to set WPS config methods");
4084            }
4085            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
4086                loge("Failed to set primary device type " + mPrimaryDeviceType);
4087            }
4088        }
4089
4090        @Override
4091        public boolean processMessage(Message message) {
4092            logStateAndMessage(message, this);
4093
4094            switch(message.what) {
4095                case WifiMonitor.SUP_CONNECTION_EVENT:
4096                    if (mVerboseLoggingEnabled) log("Supplicant connection established");
4097                    setWifiState(WIFI_STATE_ENABLED);
4098                    mSupplicantRestartCount = 0;
4099                    /* Reset the supplicant state to indicate the supplicant
4100                     * state is not known at this time */
4101                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4102                    /* Initialize data structures */
4103                    mLastBssid = null;
4104                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4105                    mLastSignalLevel = -1;
4106
4107                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
4108                    mWifiConfigManager.loadFromStore();
4109                    initializeWpsDetails();
4110                    sendSupplicantConnectionChangedBroadcast(true);
4111                    transitionTo(mSupplicantStartedState);
4112                    break;
4113                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4114                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
4115                        loge("Failed to setup control channel, restart supplicant");
4116                        mWifiMonitor.stopAllMonitoring();
4117                        try {
4118                            mClientInterface.disableSupplicant();
4119                        } catch (RemoteException e) {
4120                            // The client interface is dead, there is nothing more we can do.
4121                        }
4122                        transitionTo(mInitialState);
4123                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4124                    } else {
4125                        loge("Failed " + mSupplicantRestartCount +
4126                                " times to start supplicant, unload driver");
4127                        mSupplicantRestartCount = 0;
4128                        setWifiState(WIFI_STATE_UNKNOWN);
4129                        transitionTo(mInitialState);
4130                    }
4131                    break;
4132                case CMD_START_SUPPLICANT:
4133                case CMD_STOP_SUPPLICANT:
4134                case CMD_START_AP:
4135                case CMD_STOP_AP:
4136                case CMD_SET_OPERATIONAL_MODE:
4137                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4138                    deferMessage(message);
4139                    break;
4140                default:
4141                    return NOT_HANDLED;
4142            }
4143            return HANDLED;
4144        }
4145    }
4146
4147    class SupplicantStartedState extends State {
4148        @Override
4149        public void enter() {
4150            if (mVerboseLoggingEnabled) {
4151                logd("SupplicantStartedState enter");
4152            }
4153
4154            /* Wifi is available as long as we have a connection to supplicant */
4155            mNetworkInfo.setIsAvailable(true);
4156            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4157
4158            int defaultInterval = mContext.getResources().getInteger(
4159                    R.integer.config_wifi_supplicant_scan_interval);
4160
4161            mSupplicantScanIntervalMs = mFacade.getLongSetting(mContext,
4162                    Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
4163                    defaultInterval);
4164
4165            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
4166            mWifiNative.setExternalSim(true);
4167
4168            /* turn on use of DFS channels */
4169            mWifiNative.setDfsFlag(true);
4170
4171            setRandomMacOui();
4172            mWifiNative.enableAutoConnect(false);
4173            mCountryCode.setReadyForChange(true);
4174
4175            // We can't do this in the constructor because WifiStateMachine is created before the
4176            // wifi scanning service is initialized
4177            if (mWifiScanner == null) {
4178                mWifiScanner = mWifiInjector.getWifiScanner();
4179
4180                synchronized (mWifiReqCountLock) {
4181                    mWifiConnectivityManager = new WifiConnectivityManager(mContext,
4182                        WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo,
4183                        mWifiNetworkSelector, mWifiInjector,
4184                        getHandler().getLooper(), hasConnectionRequests());
4185                    mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);
4186                    mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);
4187                }
4188            }
4189
4190            mWifiDiagnostics.startLogging(mVerboseLoggingEnabled);
4191            mIsRunning = true;
4192            updateBatteryWorkSource(null);
4193            /**
4194             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
4195             * When this mode is on, some of the low-level scan parameters used by the
4196             * driver are changed to reduce interference with bluetooth
4197             */
4198            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4199            /* initialize network state */
4200            setNetworkDetailedState(DetailedState.DISCONNECTED);
4201
4202            // Disable legacy multicast filtering, which on some chipsets defaults to enabled.
4203            // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
4204            // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
4205            // IpManager.Callback.setFallbackMulticastFilter()
4206            mWifiNative.stopFilteringMulticastV4Packets();
4207            mWifiNative.stopFilteringMulticastV6Packets();
4208
4209            if (mOperationalMode == SCAN_ONLY_MODE ||
4210                    mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4211                mWifiNative.disconnect();
4212                if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4213                    setWifiState(WIFI_STATE_DISABLED);
4214                }
4215                transitionTo(mScanModeState);
4216            } else if (mOperationalMode == CONNECT_MODE){
4217
4218                // Status pulls in the current supplicant state and network connection state
4219                // events over the monitor connection. This helps framework sync up with
4220                // current supplicant state
4221                // TODO: actually check the supplicant status string and make sure the supplicant
4222                // is in disconnecte4d state.
4223                mWifiNative.status();
4224                // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
4225                transitionTo(mDisconnectedState);
4226            } else if (mOperationalMode == DISABLED_MODE) {
4227                transitionTo(mSupplicantStoppingState);
4228            }
4229
4230            // Set the right suspend mode settings
4231            mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
4232                    && mUserWantsSuspendOpt.get());
4233
4234            mWifiNative.setPowerSave(true);
4235
4236            if (mP2pSupported) {
4237                if (mOperationalMode == CONNECT_MODE) {
4238                    p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
4239                } else {
4240                    // P2P state machine starts in disabled state, and is not enabled until
4241                    // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
4242                    // keep it disabled.
4243                }
4244            }
4245
4246            if (mAwareSupported && mWifiAwareManager != null) {
4247                if (mOperationalMode == CONNECT_MODE) {
4248                    mWifiAwareManager.enableUsage();
4249                } else {
4250                    /*
4251                     * Aware state machine starts in disabled state. Nothing
4252                     * needed to keep it disabled.
4253                     */
4254                }
4255            }
4256
4257            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4258            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4259            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
4260            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4261
4262            // Enable link layer stats gathering
4263            mWifiNative.setWifiLinkLayerStats("wlan0", 1);
4264        }
4265
4266        @Override
4267        public boolean processMessage(Message message) {
4268            logStateAndMessage(message, this);
4269
4270            switch(message.what) {
4271                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
4272                    if (mP2pSupported) {
4273                        transitionTo(mWaitForP2pDisableState);
4274                    } else {
4275                        transitionTo(mSupplicantStoppingState);
4276                    }
4277                    break;
4278                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
4279                    loge("Connection lost, restart supplicant");
4280                    handleSupplicantConnectionLoss(true);
4281                    handleNetworkDisconnect();
4282                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4283                    if (mP2pSupported) {
4284                        transitionTo(mWaitForP2pDisableState);
4285                    } else {
4286                        transitionTo(mInitialState);
4287                    }
4288                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
4289                    break;
4290                case CMD_START_SCAN:
4291                    // TODO: remove scan request path (b/31445200)
4292                    handleScanRequest(message);
4293                    break;
4294                case WifiMonitor.SCAN_RESULTS_EVENT:
4295                case WifiMonitor.SCAN_FAILED_EVENT:
4296                    // TODO: remove handing of SCAN_RESULTS_EVENT and SCAN_FAILED_EVENT when scan
4297                    // results are retrieved from WifiScanner (b/31444878)
4298                    maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
4299                    setScanResults();
4300                    mIsScanOngoing = false;
4301                    mIsFullScanOngoing = false;
4302                    if (mBufferedScanMsg.size() > 0)
4303                        sendMessage(mBufferedScanMsg.remove());
4304                    break;
4305                case CMD_PING_SUPPLICANT:
4306                    boolean ok = mWifiNative.ping();
4307                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
4308                    break;
4309                case CMD_START_AP:
4310                    /* Cannot start soft AP while in client mode */
4311                    loge("Failed to start soft AP with a running supplicant");
4312                    setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
4313                    break;
4314                case CMD_SET_OPERATIONAL_MODE:
4315                    mOperationalMode = message.arg1;
4316                    if (mOperationalMode == DISABLED_MODE) {
4317                        transitionTo(mSupplicantStoppingState);
4318                    }
4319                    break;
4320                case CMD_TARGET_BSSID:
4321                    // Trying to associate to this BSSID
4322                    if (message.obj != null) {
4323                        mTargetRoamBSSID = (String) message.obj;
4324                    }
4325                    break;
4326                case CMD_GET_LINK_LAYER_STATS:
4327                    WifiLinkLayerStats stats = getWifiLinkLayerStats();
4328                    replyToMessage(message, message.what, stats);
4329                    break;
4330                case CMD_RESET_SIM_NETWORKS:
4331                    log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
4332                    mWifiConfigManager.resetSimNetworks();
4333                    break;
4334                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
4335                    mBluetoothConnectionActive = (message.arg1 !=
4336                            BluetoothAdapter.STATE_DISCONNECTED);
4337                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
4338                    break;
4339                case CMD_SET_SUSPEND_OPT_ENABLED:
4340                    if (message.arg1 == 1) {
4341                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
4342                        if (message.arg2 == 1) {
4343                            mSuspendWakeLock.release();
4344                        }
4345                    } else {
4346                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
4347                    }
4348                    break;
4349                case CMD_SET_HIGH_PERF_MODE:
4350                    if (message.arg1 == 1) {
4351                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
4352                    } else {
4353                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
4354                    }
4355                    break;
4356                case CMD_ENABLE_TDLS:
4357                    if (message.obj != null) {
4358                        String remoteAddress = (String) message.obj;
4359                        boolean enable = (message.arg1 == 1);
4360                        mWifiNative.startTdls(remoteAddress, enable);
4361                    }
4362                    break;
4363                case WifiMonitor.ANQP_DONE_EVENT:
4364                    // TODO(zqiu): remove this when switch over to wificond for ANQP requests.
4365                    mPasspointManager.notifyANQPDone((long) message.obj, message.arg1 != 0);
4366                    break;
4367                case CMD_STOP_IP_PACKET_OFFLOAD: {
4368                    int slot = message.arg1;
4369                    int ret = stopWifiIPPacketOffload(slot);
4370                    if (mNetworkAgent != null) {
4371                        mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
4372                    }
4373                    break;
4374                }
4375                case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4376                    // TODO(zqiu): remove this when switch over to wificond for icon requests.
4377                    IconEvent event = (IconEvent) message.obj;
4378                    mPasspointManager.notifyIconDone(event.getBSSID(), event);
4379                    break;
4380                case WifiMonitor.HS20_REMEDIATION_EVENT:
4381                    // TODO(zqiu): remove this when switch over to wificond for WNM frames
4382                    // monitoring.
4383                    mPasspointManager.receivedWnmFrame((WnmData) message.obj);
4384                    break;
4385                case CMD_CONFIG_ND_OFFLOAD:
4386                    final boolean enabled = (message.arg1 > 0);
4387                    mWifiNative.configureNeighborDiscoveryOffload(enabled);
4388                    break;
4389                case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
4390                    mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
4391                    break;
4392                case CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED:
4393                    final boolean allowed = (message.arg1 > 0);
4394                    boolean old_state = mEnableAutoJoinWhenAssociated;
4395                    mEnableAutoJoinWhenAssociated = allowed;
4396                    if (!old_state && allowed && mScreenOn
4397                            && getCurrentState() == mConnectedState) {
4398                        mWifiConnectivityManager.forceConnectivityScan();
4399                    }
4400                    break;
4401                default:
4402                    return NOT_HANDLED;
4403            }
4404            return HANDLED;
4405        }
4406
4407        @Override
4408        public void exit() {
4409            mWifiDiagnostics.stopLogging();
4410
4411            mIsRunning = false;
4412            updateBatteryWorkSource(null);
4413            mScanResults = new ArrayList<>();
4414
4415            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
4416            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4417            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
4418            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4419            mBufferedScanMsg.clear();
4420
4421            if (mAwareSupported && mWifiAwareManager != null) {
4422                mWifiAwareManager.disableUsage();
4423            }
4424
4425            mNetworkInfo.setIsAvailable(false);
4426            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4427            mCountryCode.setReadyForChange(false);
4428        }
4429    }
4430
4431    class SupplicantStoppingState extends State {
4432        @Override
4433        public void enter() {
4434            /* Send any reset commands to supplicant before shutting it down */
4435            handleNetworkDisconnect();
4436
4437            String suppState = System.getProperty("init.svc.wpa_supplicant");
4438            if (suppState == null) suppState = "unknown";
4439
4440            logd("SupplicantStoppingState: stopSupplicant "
4441                    + " init.svc.wpa_supplicant=" + suppState);
4442            mWifiMonitor.stopSupplicant();
4443
4444            /* Send ourselves a delayed message to indicate failure after a wait time */
4445            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
4446                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
4447            setWifiState(WIFI_STATE_DISABLING);
4448            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
4449        }
4450        @Override
4451        public boolean processMessage(Message message) {
4452            logStateAndMessage(message, this);
4453
4454            switch(message.what) {
4455                case WifiMonitor.SUP_CONNECTION_EVENT:
4456                    loge("Supplicant connection received while stopping");
4457                    break;
4458                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4459                    if (mVerboseLoggingEnabled) log("Supplicant connection lost");
4460                    handleSupplicantConnectionLoss(false);
4461                    transitionTo(mInitialState);
4462                    break;
4463                case CMD_STOP_SUPPLICANT_FAILED:
4464                    if (message.arg1 == mSupplicantStopFailureToken) {
4465                        loge("Timed out on a supplicant stop, kill and proceed");
4466                        handleSupplicantConnectionLoss(true);
4467                        transitionTo(mInitialState);
4468                    }
4469                    break;
4470                case CMD_START_SUPPLICANT:
4471                case CMD_STOP_SUPPLICANT:
4472                case CMD_START_AP:
4473                case CMD_STOP_AP:
4474                case CMD_SET_OPERATIONAL_MODE:
4475                    deferMessage(message);
4476                    break;
4477                default:
4478                    return NOT_HANDLED;
4479            }
4480            return HANDLED;
4481        }
4482    }
4483
4484    class WaitForP2pDisableState extends State {
4485        private State mTransitionToState;
4486        @Override
4487        public void enter() {
4488            switch (getCurrentMessage().what) {
4489                case WifiMonitor.SUP_DISCONNECTION_EVENT:
4490                    mTransitionToState = mInitialState;
4491                    break;
4492                case CMD_STOP_SUPPLICANT:
4493                default:
4494                    mTransitionToState = mSupplicantStoppingState;
4495                    break;
4496            }
4497            p2pSendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
4498        }
4499        @Override
4500        public boolean processMessage(Message message) {
4501            logStateAndMessage(message, this);
4502
4503            switch(message.what) {
4504                case WifiStateMachine.CMD_DISABLE_P2P_RSP:
4505                    transitionTo(mTransitionToState);
4506                    break;
4507                /* Defer wifi start/shut and driver commands */
4508                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4509                case CMD_START_SUPPLICANT:
4510                case CMD_STOP_SUPPLICANT:
4511                case CMD_START_AP:
4512                case CMD_STOP_AP:
4513                case CMD_SET_OPERATIONAL_MODE:
4514                case CMD_START_SCAN:
4515                case CMD_DISCONNECT:
4516                case CMD_REASSOCIATE:
4517                case CMD_RECONNECT:
4518                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
4519                    deferMessage(message);
4520                    break;
4521                default:
4522                    return NOT_HANDLED;
4523            }
4524            return HANDLED;
4525        }
4526    }
4527
4528    class ScanModeState extends State {
4529        private int mLastOperationMode;
4530        @Override
4531        public void enter() {
4532            mLastOperationMode = mOperationalMode;
4533        }
4534        @Override
4535        public boolean processMessage(Message message) {
4536            logStateAndMessage(message, this);
4537
4538            switch(message.what) {
4539                case CMD_SET_OPERATIONAL_MODE:
4540                    if (message.arg1 == CONNECT_MODE) {
4541                        if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4542                            setWifiState(WIFI_STATE_ENABLED);
4543                            // Load and re-enable networks when going back to enabled state
4544                            // This is essential for networks to show up after restore
4545                            mWifiConfigManager.loadFromStore();
4546                            p2pSendMessage(CMD_ENABLE_P2P);
4547                        }
4548                        mOperationalMode = CONNECT_MODE;
4549                        transitionTo(mDisconnectedState);
4550                    } else if (message.arg1 == DISABLED_MODE) {
4551                        transitionTo(mSupplicantStoppingState);
4552                    }
4553                    // Nothing to do
4554                    break;
4555                // Handle scan. All the connection related commands are
4556                // handled only in ConnectModeState
4557                case CMD_START_SCAN:
4558                    handleScanRequest(message);
4559                    break;
4560                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4561                    SupplicantState state = handleSupplicantStateChange(message);
4562                    if (mVerboseLoggingEnabled) log("SupplicantState= " + state);
4563                    break;
4564                default:
4565                    return NOT_HANDLED;
4566            }
4567            return HANDLED;
4568        }
4569    }
4570
4571
4572    String smToString(Message message) {
4573        return smToString(message.what);
4574    }
4575
4576    String smToString(int what) {
4577        String s = sSmToString.get(what);
4578        if (s != null) {
4579            return s;
4580        }
4581        switch (what) {
4582            case WifiMonitor.DRIVER_HUNG_EVENT:
4583                s = "DRIVER_HUNG_EVENT";
4584                break;
4585            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
4586                s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
4587                break;
4588            case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
4589                s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
4590                break;
4591            case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4592                s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
4593                break;
4594            case WifiManager.DISABLE_NETWORK:
4595                s = "WifiManager.DISABLE_NETWORK";
4596                break;
4597            case WifiManager.CONNECT_NETWORK:
4598                s = "CONNECT_NETWORK";
4599                break;
4600            case WifiManager.SAVE_NETWORK:
4601                s = "SAVE_NETWORK";
4602                break;
4603            case WifiManager.FORGET_NETWORK:
4604                s = "FORGET_NETWORK";
4605                break;
4606            case WifiMonitor.SUP_CONNECTION_EVENT:
4607                s = "SUP_CONNECTION_EVENT";
4608                break;
4609            case WifiMonitor.SUP_DISCONNECTION_EVENT:
4610                s = "SUP_DISCONNECTION_EVENT";
4611                break;
4612            case WifiMonitor.SCAN_RESULTS_EVENT:
4613                s = "SCAN_RESULTS_EVENT";
4614                break;
4615            case WifiMonitor.SCAN_FAILED_EVENT:
4616                s = "SCAN_FAILED_EVENT";
4617                break;
4618            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4619                s = "SUPPLICANT_STATE_CHANGE_EVENT";
4620                break;
4621            case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4622                s = "AUTHENTICATION_FAILURE_EVENT";
4623                break;
4624            case WifiMonitor.SSID_TEMP_DISABLED:
4625                s = "SSID_TEMP_DISABLED";
4626                break;
4627            case WifiMonitor.SSID_REENABLED:
4628                s = "SSID_REENABLED";
4629                break;
4630            case WifiMonitor.WPS_SUCCESS_EVENT:
4631                s = "WPS_SUCCESS_EVENT";
4632                break;
4633            case WifiMonitor.WPS_FAIL_EVENT:
4634                s = "WPS_FAIL_EVENT";
4635                break;
4636            case WifiMonitor.SUP_REQUEST_IDENTITY:
4637                s = "SUP_REQUEST_IDENTITY";
4638                break;
4639            case WifiMonitor.NETWORK_CONNECTION_EVENT:
4640                s = "NETWORK_CONNECTION_EVENT";
4641                break;
4642            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4643                s = "NETWORK_DISCONNECTION_EVENT";
4644                break;
4645            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4646                s = "ASSOCIATION_REJECTION_EVENT";
4647                break;
4648            case WifiMonitor.ANQP_DONE_EVENT:
4649                s = "WifiMonitor.ANQP_DONE_EVENT";
4650                break;
4651            case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
4652                s = "WifiMonitor.RX_HS20_ANQP_ICON_EVENT";
4653                break;
4654            case WifiMonitor.GAS_QUERY_DONE_EVENT:
4655                s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
4656                break;
4657            case WifiMonitor.HS20_REMEDIATION_EVENT:
4658                s = "WifiMonitor.HS20_REMEDIATION_EVENT";
4659                break;
4660            case WifiMonitor.GAS_QUERY_START_EVENT:
4661                s = "WifiMonitor.GAS_QUERY_START_EVENT";
4662                break;
4663            case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
4664                s = "GROUP_CREATING_TIMED_OUT";
4665                break;
4666            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
4667                s = "P2P_CONNECTION_CHANGED";
4668                break;
4669            case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
4670                s = "P2P.DISCONNECT_WIFI_RESPONSE";
4671                break;
4672            case WifiP2pServiceImpl.SET_MIRACAST_MODE:
4673                s = "P2P.SET_MIRACAST_MODE";
4674                break;
4675            case WifiP2pServiceImpl.BLOCK_DISCOVERY:
4676                s = "P2P.BLOCK_DISCOVERY";
4677                break;
4678            case WifiManager.CANCEL_WPS:
4679                s = "CANCEL_WPS";
4680                break;
4681            case WifiManager.CANCEL_WPS_FAILED:
4682                s = "CANCEL_WPS_FAILED";
4683                break;
4684            case WifiManager.CANCEL_WPS_SUCCEDED:
4685                s = "CANCEL_WPS_SUCCEDED";
4686                break;
4687            case WifiManager.START_WPS:
4688                s = "START_WPS";
4689                break;
4690            case WifiManager.START_WPS_SUCCEEDED:
4691                s = "START_WPS_SUCCEEDED";
4692                break;
4693            case WifiManager.WPS_FAILED:
4694                s = "WPS_FAILED";
4695                break;
4696            case WifiManager.WPS_COMPLETED:
4697                s = "WPS_COMPLETED";
4698                break;
4699            case WifiManager.RSSI_PKTCNT_FETCH:
4700                s = "RSSI_PKTCNT_FETCH";
4701                break;
4702            default:
4703                s = "what:" + Integer.toString(what);
4704                break;
4705        }
4706        return s;
4707    }
4708
4709    void registerConnected() {
4710        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4711            mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId);
4712            // On connect, reset wifiScoreReport
4713            mWifiScoreReport.reset();
4714       }
4715    }
4716
4717    void registerDisconnected() {
4718        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4719            mWifiConfigManager.updateNetworkAfterDisconnect(mLastNetworkId);
4720            // We are switching away from this configuration,
4721            // hence record the time we were connected last
4722            WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
4723            if (config != null) {
4724                if (config.ephemeral) {
4725                    // Remove ephemeral WifiConfigurations from file
4726                    mWifiConfigManager.removeNetwork(mLastNetworkId, Process.WIFI_UID);
4727                }
4728            }
4729        }
4730    }
4731
4732    void noteWifiDisabledWhileAssociated() {
4733        // We got disabled by user while we were associated, make note of it
4734        int rssi = mWifiInfo.getRssi();
4735        WifiConfiguration config = getCurrentWifiConfiguration();
4736        if (getCurrentState() == mConnectedState
4737                && rssi != WifiInfo.INVALID_RSSI
4738                && config != null) {
4739            boolean is24GHz = mWifiInfo.is24GHz();
4740            boolean isBadRSSI = (is24GHz && rssi < mThresholdMinimumRssi24)
4741                    || (!is24GHz && rssi < mThresholdMinimumRssi5);
4742            boolean isLowRSSI =
4743                    (is24GHz && rssi < mThresholdQualifiedRssi24)
4744                            || (!is24GHz && mWifiInfo.getRssi() < mThresholdQualifiedRssi5);
4745            boolean isHighRSSI = (is24GHz && rssi >= mThresholdSaturatedRssi24)
4746                    || (!is24GHz && mWifiInfo.getRssi() >= mThresholdSaturatedRssi5);
4747            if (isBadRSSI) {
4748                // Take note that we got disabled while RSSI was Bad
4749                config.numUserTriggeredWifiDisableLowRSSI++;
4750            } else if (isLowRSSI) {
4751                // Take note that we got disabled while RSSI was Low
4752                config.numUserTriggeredWifiDisableBadRSSI++;
4753            } else if (!isHighRSSI) {
4754                // Take note that we got disabled while RSSI was Not high
4755                config.numUserTriggeredWifiDisableNotHighRSSI++;
4756            }
4757            mWifiConfigManager.setNetworkRSSIStats(
4758                    config.networkId,
4759                    config.numUserTriggeredWifiDisableLowRSSI,
4760                    config.numUserTriggeredWifiDisableBadRSSI,
4761                    config.numUserTriggeredWifiDisableNotHighRSSI,
4762                    config.numTicksAtLowRSSI,
4763                    config.numTicksAtBadRSSI,
4764                    config.numTicksAtNotHighRSSI);
4765        }
4766    }
4767
4768    /**
4769     * Returns Wificonfiguration object correponding to the currently connected network, null if
4770     * not connected.
4771     */
4772    public WifiConfiguration getCurrentWifiConfiguration() {
4773        if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
4774            return null;
4775        }
4776        return mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
4777    }
4778
4779    ScanResult getCurrentScanResult() {
4780        WifiConfiguration config = getCurrentWifiConfiguration();
4781        if (config == null) {
4782            return null;
4783        }
4784        String BSSID = mWifiInfo.getBSSID();
4785        if (BSSID == null) {
4786            BSSID = mTargetRoamBSSID;
4787        }
4788        ScanDetailCache scanDetailCache =
4789                mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
4790
4791        if (scanDetailCache == null) {
4792            return null;
4793        }
4794
4795        return scanDetailCache.get(BSSID);
4796    }
4797
4798    String getCurrentBSSID() {
4799        if (isLinkDebouncing()) {
4800            return null;
4801        }
4802        return mLastBssid;
4803    }
4804
4805    class ConnectModeState extends State {
4806
4807        @Override
4808        public void enter() {
4809            // Inform WifiConnectivityManager that Wifi is enabled
4810            mWifiConnectivityManager.setWifiEnabled(true);
4811            // Inform metrics that Wifi is Enabled (but not yet connected)
4812            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
4813        }
4814
4815        @Override
4816        public void exit() {
4817            // Inform WifiConnectivityManager that Wifi is disabled
4818            mWifiConnectivityManager.setWifiEnabled(false);
4819            // Inform metrics that Wifi is being disabled (Toggled, airplane enabled, etc)
4820            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISABLED);
4821        }
4822
4823        @Override
4824        public boolean processMessage(Message message) {
4825            WifiConfiguration config;
4826            int netId;
4827            boolean ok;
4828            boolean didDisconnect;
4829            String bssid;
4830            String ssid;
4831            NetworkUpdateResult result;
4832            logStateAndMessage(message, this);
4833
4834            switch (message.what) {
4835                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4836                    mWifiDiagnostics.captureBugReportData(
4837                            WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
4838                    didBlackListBSSID = false;
4839                    bssid = (String) message.obj;
4840                    if (bssid == null || TextUtils.isEmpty(bssid)) {
4841                        // If BSSID is null, use the target roam BSSID
4842                        bssid = mTargetRoamBSSID;
4843                    }
4844                    if (bssid != null) {
4845                        // If we have a BSSID, tell configStore to black list it
4846                        didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid, false);
4847                    }
4848                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
4849                            WifiConfiguration.NetworkSelectionStatus
4850                            .DISABLED_ASSOCIATION_REJECTION);
4851                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
4852                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
4853                    reportConnectionAttemptEnd(
4854                            WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
4855                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
4856                    mWifiInjector.getWifiLastResortWatchdog()
4857                            .noteConnectionFailureAndTriggerIfNeeded(
4858                                    getTargetSsid(), bssid,
4859                                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
4860                    break;
4861                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4862                    mWifiDiagnostics.captureBugReportData(
4863                            WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
4864                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
4865                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
4866                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
4867                                WifiConfiguration.NetworkSelectionStatus
4868                                        .DISABLED_AUTHENTICATION_FAILURE);
4869                    }
4870                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
4871                    reportConnectionAttemptEnd(
4872                            WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
4873                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
4874                    mWifiInjector.getWifiLastResortWatchdog()
4875                            .noteConnectionFailureAndTriggerIfNeeded(
4876                                    getTargetSsid(), mTargetRoamBSSID,
4877                                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
4878                    break;
4879                case WifiMonitor.SSID_TEMP_DISABLED:
4880                    netId = lookupFrameworkNetworkId(message.arg1);
4881                    Log.e(TAG, "Supplicant SSID temporary disabled:"
4882                            + mWifiConfigManager.getConfiguredNetwork(netId));
4883                    mWifiConfigManager.updateNetworkSelectionStatus(
4884                            netId,
4885                            WifiConfiguration.NetworkSelectionStatus
4886                            .DISABLED_AUTHENTICATION_FAILURE);
4887                    reportConnectionAttemptEnd(
4888                            WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED,
4889                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
4890                    mWifiInjector.getWifiLastResortWatchdog()
4891                            .noteConnectionFailureAndTriggerIfNeeded(
4892                                    getTargetSsid(), mTargetRoamBSSID,
4893                                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
4894                    break;
4895                case WifiMonitor.SSID_REENABLED:
4896                    netId = lookupFrameworkNetworkId(message.arg1);
4897                    Log.d(TAG, "Supplicant SSID reenable:"
4898                            + mWifiConfigManager.getConfiguredNetwork(netId));
4899                    // Do not re-enable it in Quality Network Selection since framework has its own
4900                    // Algorithm of disable/enable
4901                    break;
4902                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4903                    SupplicantState state = handleSupplicantStateChange(message);
4904                    // A driver/firmware hang can now put the interface in a down state.
4905                    // We detect the interface going down and recover from it
4906                    if (!SupplicantState.isDriverActive(state)) {
4907                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
4908                            handleNetworkDisconnect();
4909                        }
4910                        log("Detected an interface down, restart driver");
4911                        // Rely on the fact that this will force us into killing supplicant and then
4912                        // restart supplicant from a clean state.
4913                        transitionTo(mSupplicantStoppingState);
4914                        sendMessage(CMD_START_SUPPLICANT);
4915                        break;
4916                    }
4917
4918                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
4919                    // when authentication times out after a successful connection,
4920                    // we can figure this from the supplicant state. If supplicant
4921                    // state is DISCONNECTED, but the mNetworkInfo says we are not
4922                    // disconnected, we need to handle a disconnection
4923                    if (!isLinkDebouncing() && state == SupplicantState.DISCONNECTED &&
4924                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
4925                        if (mVerboseLoggingEnabled) {
4926                            log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
4927                        }
4928                        handleNetworkDisconnect();
4929                        transitionTo(mDisconnectedState);
4930                    }
4931
4932                    // If we have COMPLETED a connection to a BSSID, start doing
4933                    // DNAv4/DNAv6 -style probing for on-link neighbors of
4934                    // interest (e.g. routers); harmless if none are configured.
4935                    if (state == SupplicantState.COMPLETED) {
4936                        mIpManager.confirmConfiguration();
4937                    }
4938                    break;
4939                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
4940                    if (message.arg1 == 1) {
4941                        mWifiNative.disconnect();
4942                        mTemporarilyDisconnectWifi = true;
4943                    } else {
4944                        mWifiNative.reconnect();
4945                        mTemporarilyDisconnectWifi = false;
4946                    }
4947                    break;
4948                case CMD_ADD_OR_UPDATE_NETWORK:
4949                    config = (WifiConfiguration) message.obj;
4950                    result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
4951                    if (!result.isSuccess()) {
4952                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
4953                    }
4954                    replyToMessage(message, message.what, result.getNetworkId());
4955                    break;
4956                case CMD_REMOVE_NETWORK:
4957                    netId = message.arg1;
4958                    ok = mWifiConfigManager.removeNetwork(message.arg1, message.sendingUid);
4959                    if (!ok) {
4960                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
4961                    } else if (netId == mTargetNetworkId || netId == mLastNetworkId) {
4962                        // Disconnect and let autojoin reselect a new network
4963                        sendMessage(CMD_DISCONNECT);
4964                    }
4965                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
4966                    break;
4967                case CMD_ENABLE_NETWORK:
4968                    boolean disableOthers = message.arg2 == 1;
4969                    netId = message.arg1;
4970                    if (disableOthers) {
4971                        // If the app has all the necessary permissions, this will trigger a connect
4972                        // attempt.
4973                        ok = connectToUserSelectNetwork(netId, message.sendingUid);
4974                    } else {
4975                        ok = mWifiConfigManager.enableNetwork(netId, false, message.sendingUid);
4976                    }
4977                    if (!ok) {
4978                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
4979                    }
4980                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
4981                    break;
4982                case WifiManager.DISABLE_NETWORK:
4983                    netId = message.arg1;
4984                    if (mWifiConfigManager.disableNetwork(netId, message.sendingUid)) {
4985                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
4986                        if (netId == mTargetNetworkId || netId == mLastNetworkId) {
4987                            // Disconnect and let autojoin reselect a new network
4988                            sendMessage(CMD_DISCONNECT);
4989                        }
4990                    } else {
4991                        loge("Failed to remove network");
4992                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
4993                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
4994                                WifiManager.ERROR);
4995                    }
4996                    break;
4997                case CMD_DISABLE_EPHEMERAL_NETWORK:
4998                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
4999                    if (config != null) {
5000                        if (config.networkId == mTargetNetworkId
5001                                || config.networkId == mLastNetworkId) {
5002                            // Disconnect and let autojoin reselect a new network
5003                            sendMessage(CMD_DISCONNECT);
5004                        }
5005                    }
5006                    break;
5007                case CMD_SAVE_CONFIG:
5008                    ok = mWifiConfigManager.saveToStore(true);
5009                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
5010                    // Inform the backup manager about a data change
5011                    mBackupManagerProxy.notifyDataChanged();
5012                    break;
5013                case CMD_GET_CONFIGURED_NETWORKS:
5014                    replyToMessage(message, message.what,
5015                            mWifiConfigManager.getSavedNetworks());
5016                    break;
5017                case WifiMonitor.SUP_REQUEST_IDENTITY:
5018                    int supplicantNetworkId = message.arg2;
5019                    netId = lookupFrameworkNetworkId(supplicantNetworkId);
5020                    boolean identitySent = false;
5021                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
5022                    if (targetWificonfiguration != null
5023                            && targetWificonfiguration.enterpriseConfig != null) {
5024                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
5025                    }
5026                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
5027                    if (targetWificonfiguration != null
5028                            && targetWificonfiguration.networkId == netId
5029                            && (targetWificonfiguration.allowedKeyManagement
5030                                    .get(WifiConfiguration.KeyMgmt.WPA_EAP)
5031                            || targetWificonfiguration.allowedKeyManagement
5032                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X))
5033                            && TelephonyUtil.isSimEapMethod(eapMethod)) {
5034                        String identity =
5035                                TelephonyUtil.getSimIdentity(getTelephonyManager(), eapMethod);
5036                        if (identity != null) {
5037                            mWifiNative.simIdentityResponse(supplicantNetworkId, identity);
5038                            identitySent = true;
5039                        }
5040                    }
5041                    if (!identitySent) {
5042                        // Supplicant lacks credentials to connect to that network, hence black list
5043                        ssid = (String) message.obj;
5044                        if (targetWificonfiguration != null && ssid != null
5045                                && targetWificonfiguration.SSID != null
5046                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
5047                            mWifiConfigManager.updateNetworkSelectionStatus(
5048                                    targetWificonfiguration.networkId,
5049                                    WifiConfiguration.NetworkSelectionStatus
5050                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
5051                        }
5052                        mWifiNative.disconnect();
5053                    }
5054                    break;
5055                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5056                    logd("Received SUP_REQUEST_SIM_AUTH");
5057                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
5058                    if (requestData != null) {
5059                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
5060                            handleGsmAuthRequest(requestData);
5061                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
5062                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
5063                            handle3GAuthRequest(requestData);
5064                        }
5065                    } else {
5066                        loge("Invalid sim auth request");
5067                    }
5068                    break;
5069                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5070                    replyToMessage(message, message.what,
5071                            mWifiConfigManager.getConfiguredNetworksWithPasswords());
5072                    break;
5073                case CMD_GET_MATCHING_CONFIG:
5074                    // TODO(b/31065385)
5075                    replyToMessage(message, message.what, null);
5076                    break;
5077                case CMD_RECONNECT:
5078                    mWifiConnectivityManager.forceConnectivityScan();
5079                    break;
5080                case CMD_REASSOCIATE:
5081                    lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5082                    mWifiNative.reassociate();
5083                    break;
5084                case CMD_RELOAD_TLS_AND_RECONNECT:
5085                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
5086                        logd("Reconnecting to give a chance to un-connected TLS networks");
5087                        mWifiNative.disconnect();
5088                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5089                        mWifiNative.reconnect();
5090                    }
5091                    break;
5092                case CMD_START_ROAM:
5093                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5094                    return HANDLED;
5095                case CMD_START_CONNECT:
5096                    /* connect command coming from auto-join */
5097                    netId = message.arg1;
5098                    bssid = (String) message.obj;
5099                    config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
5100                    logd("CMD_START_CONNECT sup state "
5101                            + mSupplicantStateTracker.getSupplicantStateName()
5102                            + " my state " + getCurrentState().getName()
5103                            + " nid=" + Integer.toString(netId)
5104                            + " roam=" + Boolean.toString(mAutoRoaming));
5105                    if (config == null) {
5106                        loge("CMD_START_CONNECT and no config, bail out...");
5107                        break;
5108                    }
5109                    mTargetNetworkId = netId;
5110                    setTargetBssid(config, bssid);
5111
5112                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
5113                            WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
5114                    boolean shouldDisconnect = (getCurrentState() != mDisconnectedState);
5115                    if (mWifiSupplicantControl.connectToNetwork(config, shouldDisconnect)) {
5116                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
5117                        targetWificonfiguration = config;
5118                        mAutoRoaming = false;
5119                        if (isRoaming() || isLinkDebouncing()) {
5120                            transitionTo(mRoamingState);
5121                        } else if (shouldDisconnect) {
5122                            transitionTo(mDisconnectingState);
5123                        } else {
5124                            transitionTo(mDisconnectedState);
5125                        }
5126                    } else {
5127                        loge("CMD_START_CONNECT Failed to start connection to network " + config);
5128                        reportConnectionAttemptEnd(
5129                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
5130                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5131                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5132                                WifiManager.ERROR);
5133                        break;
5134                    }
5135                    break;
5136                case CMD_REMOVE_APP_CONFIGURATIONS:
5137                    mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
5138                    break;
5139                case CMD_REMOVE_USER_CONFIGURATIONS:
5140                    mWifiConfigManager.removeNetworksForUser(message.arg1);
5141                    break;
5142                case WifiManager.CONNECT_NETWORK:
5143                    /**
5144                     * The connect message can contain a network id passed as arg1 on message or
5145                     * or a config passed as obj on message.
5146                     * For a new network, a config is passed to create and connect.
5147                     * For an existing network, a network id is passed
5148                     */
5149                    netId = message.arg1;
5150                    config = (WifiConfiguration) message.obj;
5151                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5152                    // New network addition.
5153                    if (config != null) {
5154                        result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5155                        if (!result.isSuccess()) {
5156                            loge("CONNECT_NETWORK adding/updating config=" + config + " failed");
5157                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5158                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5159                                    WifiManager.ERROR);
5160                            break;
5161                        }
5162                        netId = result.getNetworkId();
5163                    }
5164                    if (!connectToUserSelectNetwork(netId, message.sendingUid)) {
5165                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5166                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5167                                WifiManager.NOT_AUTHORIZED);
5168                        break;
5169                    }
5170                    broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
5171                    replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
5172                    break;
5173                case WifiManager.SAVE_NETWORK:
5174                    config = (WifiConfiguration) message.obj;
5175                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
5176                    if (config == null) {
5177                        loge("SAVE_NETWORK with null configuration"
5178                                + mSupplicantStateTracker.getSupplicantStateName()
5179                                + " my state " + getCurrentState().getName());
5180                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5181                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5182                                WifiManager.ERROR);
5183                        break;
5184                    }
5185                    result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
5186                    if (!result.isSuccess()) {
5187                        loge("SAVE_NETWORK adding/updating config=" + config + " failed");
5188                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5189                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5190                                WifiManager.ERROR);
5191                        break;
5192                    }
5193                    netId = result.getNetworkId();
5194                    if (mWifiInfo.getNetworkId() == netId) {
5195                        if (result.hasIpChanged()) {
5196                            // The currently connection configuration was changed
5197                            // We switched from DHCP to static or from static to DHCP, or the
5198                            // static IP address has changed.
5199                            log("Reconfiguring IP on connection");
5200                            // TODO: clear addresses and disable IPv6
5201                            // to simplify obtainingIpState.
5202                            transitionTo(mObtainingIpState);
5203                        }
5204                        if (result.hasProxyChanged()) {
5205                            log("Reconfiguring proxy on connection");
5206                            mIpManager.setHttpProxy(
5207                                    getCurrentWifiConfiguration().getHttpProxy());
5208                        }
5209                    } else {
5210                        if (!connectToUserSelectNetwork(netId, message.sendingUid)) {
5211                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5212                            replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5213                                    WifiManager.NOT_AUTHORIZED);
5214                            break;
5215                        }
5216                    }
5217                    broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
5218                    replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
5219                    break;
5220                case WifiManager.FORGET_NETWORK:
5221                    netId = message.arg1;
5222                    if (mWifiConfigManager.removeNetwork(netId, message.sendingUid)) {
5223                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
5224                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
5225                                (WifiConfiguration) message.obj);
5226                        if (netId == mTargetNetworkId || netId == mLastNetworkId) {
5227                            // Disconnect and let autojoin reselect a new network
5228                            sendMessage(CMD_DISCONNECT);
5229                        }
5230                    } else {
5231                        loge("Failed to forget network");
5232                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5233                                WifiManager.ERROR);
5234                    }
5235                    break;
5236                case WifiManager.START_WPS:
5237                    WpsInfo wpsInfo = (WpsInfo) message.obj;
5238                    WpsResult wpsResult;
5239                    switch (wpsInfo.setup) {
5240                        case WpsInfo.PBC:
5241                            wpsResult = mWifiSupplicantControl.startWpsPbc(wpsInfo);
5242                            break;
5243                        case WpsInfo.KEYPAD:
5244                            wpsResult =
5245                                    mWifiSupplicantControl.startWpsWithPinFromAccessPoint(wpsInfo);
5246                            break;
5247                        case WpsInfo.DISPLAY:
5248                            wpsResult = mWifiSupplicantControl.startWpsWithPinFromDevice(wpsInfo);
5249                            break;
5250                        default:
5251                            wpsResult = new WpsResult(Status.FAILURE);
5252                            loge("Invalid setup for WPS");
5253                            break;
5254                    }
5255                    if (wpsResult.status == Status.SUCCESS) {
5256                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
5257                        transitionTo(mWpsRunningState);
5258                    } else {
5259                        loge("Failed to start WPS with config " + wpsInfo.toString());
5260                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
5261                    }
5262                    break;
5263                case CMD_ASSOCIATED_BSSID:
5264                    // This is where we can confirm the connection BSSID. Use it to find the
5265                    // right ScanDetail to populate metrics.
5266                    String someBssid = (String) message.obj;
5267                    if (someBssid != null) {
5268                        // Get the ScanDetail associated with this BSSID.
5269                        ScanDetailCache scanDetailCache =
5270                                mWifiConfigManager.getScanDetailCacheForNetwork(mTargetNetworkId);
5271                        if (scanDetailCache != null) {
5272                            mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
5273                                    someBssid));
5274                        }
5275                    }
5276                    return NOT_HANDLED;
5277                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5278                    if (mVerboseLoggingEnabled) log("Network connection established");
5279                    mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
5280                    mLastBssid = (String) message.obj;
5281
5282                    mWifiInfo.setBSSID(mLastBssid);
5283                    mWifiInfo.setNetworkId(mLastNetworkId);
5284                    mWifiConnectivityManager.trackBssid(mLastBssid, true);
5285                    sendNetworkStateChangeBroadcast(mLastBssid);
5286                    transitionTo(mObtainingIpState);
5287                    break;
5288                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5289                    // Calling handleNetworkDisconnect here is redundant because we might already
5290                    // have called it when leaving L2ConnectedState to go to disconnecting state
5291                    // or thru other path
5292                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
5293                    // if they are valid, and only in this case call handleNEtworkDisconnect,
5294                    // TODO: this should be fixed for a L MR release
5295                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
5296                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
5297                    // at the chip etc...
5298                    if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
5299                    handleNetworkDisconnect();
5300                    transitionTo(mDisconnectedState);
5301                    break;
5302                case CMD_ADD_PASSPOINT_MO:
5303                    // TODO(b/31065385): Passpoint config management.
5304                    replyToMessage(message, message.what, 0);
5305                    break;
5306                case CMD_MODIFY_PASSPOINT_MO:
5307                    // TODO(b/31065385): Passpoint config management.
5308                    replyToMessage(message, message.what, 0);
5309                    break;
5310                case CMD_QUERY_OSU_ICON:
5311                    mPasspointManager.queryPasspointIcon(
5312                            ((Bundle) message.obj).getLong(EXTRA_OSU_ICON_QUERY_BSSID),
5313                            ((Bundle) message.obj).getString(EXTRA_OSU_ICON_QUERY_FILENAME));
5314                    break;
5315                case CMD_MATCH_PROVIDER_NETWORK:
5316                    // TODO(b/31065385): Passpoint config management.
5317                    replyToMessage(message, message.what, 0);
5318                    break;
5319                default:
5320                    return NOT_HANDLED;
5321            }
5322            return HANDLED;
5323        }
5324    }
5325
5326    private void updateCapabilities(WifiConfiguration config) {
5327        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
5328        if (config != null) {
5329            if (config.ephemeral) {
5330                networkCapabilities.removeCapability(
5331                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5332            } else {
5333                networkCapabilities.addCapability(
5334                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
5335            }
5336
5337            networkCapabilities.setSignalStrength(
5338                    (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI)
5339                    ? mWifiInfo.getRssi()
5340                    : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
5341        }
5342
5343        if (mWifiInfo.getMeteredHint()) {
5344            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
5345        }
5346
5347        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
5348    }
5349
5350    private class WifiNetworkAgent extends NetworkAgent {
5351        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
5352                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
5353            super(l, c, TAG, ni, nc, lp, score, misc);
5354        }
5355
5356        @Override
5357        protected void unwanted() {
5358            // Ignore if we're not the current networkAgent.
5359            if (this != mNetworkAgent) return;
5360            if (mVerboseLoggingEnabled) {
5361                log("WifiNetworkAgent -> Wifi unwanted score " + Integer.toString(mWifiInfo.score));
5362            }
5363            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
5364        }
5365
5366        @Override
5367        protected void networkStatus(int status, String redirectUrl) {
5368            if (this != mNetworkAgent) return;
5369            if (status == NetworkAgent.INVALID_NETWORK) {
5370                if (mVerboseLoggingEnabled) {
5371                    log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
5372                            + Integer.toString(mWifiInfo.score));
5373                }
5374                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
5375            } else if (status == NetworkAgent.VALID_NETWORK) {
5376                if (mVerboseLoggingEnabled) {
5377                    log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
5378                            + Integer.toString(mWifiInfo.score));
5379                }
5380                doNetworkStatus(status);
5381            }
5382        }
5383
5384        @Override
5385        protected void saveAcceptUnvalidated(boolean accept) {
5386            if (this != mNetworkAgent) return;
5387            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
5388        }
5389
5390        @Override
5391        protected void startPacketKeepalive(Message msg) {
5392            WifiStateMachine.this.sendMessage(
5393                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5394        }
5395
5396        @Override
5397        protected void stopPacketKeepalive(Message msg) {
5398            WifiStateMachine.this.sendMessage(
5399                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
5400        }
5401
5402        @Override
5403        protected void setSignalStrengthThresholds(int[] thresholds) {
5404            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
5405            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
5406            //    MAX_VALUE at the start/end of the thresholds array if necessary.
5407            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
5408            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
5409            //    re-arm the hardware event. This needs to be done on the state machine thread to
5410            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
5411            //    sent in the NetworkCapabilities) must be the one received from the hardware event
5412            //    received, or we might skip callbacks.
5413            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
5414            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
5415            if (thresholds.length == 0) {
5416                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5417                        mWifiInfo.getRssi());
5418                return;
5419            }
5420            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
5421            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
5422            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
5423            Arrays.sort(rssiVals);
5424            byte[] rssiRange = new byte[rssiVals.length];
5425            for (int i = 0; i < rssiVals.length; i++) {
5426                int val = rssiVals[i];
5427                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
5428                    rssiRange[i] = (byte) val;
5429                } else {
5430                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
5431                            + Arrays.toString(rssiVals));
5432                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
5433                            mWifiInfo.getRssi());
5434                    return;
5435                }
5436            }
5437            // TODO: Do we quash rssi values in this sorted array which are very close?
5438            mRssiRanges = rssiRange;
5439            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
5440                    mWifiInfo.getRssi());
5441        }
5442
5443        @Override
5444        protected void preventAutomaticReconnect() {
5445            if (this != mNetworkAgent) return;
5446            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
5447        }
5448    }
5449
5450    void unwantedNetwork(int reason) {
5451        sendMessage(CMD_UNWANTED_NETWORK, reason);
5452    }
5453
5454    void doNetworkStatus(int status) {
5455        sendMessage(CMD_NETWORK_STATUS, status);
5456    }
5457
5458    // rfc4186 & rfc4187:
5459    // create Permanent Identity base on IMSI,
5460    // identity = usernam@realm
5461    // with username = prefix | IMSI
5462    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
5463    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
5464        String mcc;
5465        String mnc;
5466        String prefix;
5467
5468        if (imsi == null || imsi.isEmpty())
5469            return "";
5470
5471        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
5472            prefix = "1";
5473        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
5474            prefix = "0";
5475        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
5476            prefix = "6";
5477        else  // not a valide EapMethod
5478            return "";
5479
5480        /* extract mcc & mnc from mccMnc */
5481        if (mccMnc != null && !mccMnc.isEmpty()) {
5482            mcc = mccMnc.substring(0, 3);
5483            mnc = mccMnc.substring(3);
5484            if (mnc.length() == 2)
5485                mnc = "0" + mnc;
5486        } else {
5487            // extract mcc & mnc from IMSI, assume mnc size is 3
5488            mcc = imsi.substring(0, 3);
5489            mnc = imsi.substring(3, 6);
5490        }
5491
5492        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
5493    }
5494
5495    boolean startScanForConfiguration(WifiConfiguration config) {
5496        if (config == null)
5497            return false;
5498
5499        // We are still seeing a fairly high power consumption triggered by autojoin scans
5500        // Hence do partial scans only for PSK configuration that are roamable since the
5501        // primary purpose of the partial scans is roaming.
5502        // Full badn scans with exponential backoff for the purpose or extended roaming and
5503        // network switching are performed unconditionally.
5504        ScanDetailCache scanDetailCache =
5505                mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
5506        if (scanDetailCache == null
5507                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
5508                || scanDetailCache.size() > 6) {
5509            //return true but to not trigger the scan
5510            return true;
5511        }
5512        Set<Integer> freqs =
5513                mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(
5514                        config.networkId, ONE_HOUR_MILLI);
5515        if (freqs != null && freqs.size() != 0) {
5516            //if (mVerboseLoggingEnabled) {
5517            logd("starting scan for " + config.configKey() + " with " + freqs);
5518            //}
5519            List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks = new ArrayList<>();
5520            if (config.hiddenSSID) {
5521                hiddenNetworks.add(new WifiScanner.ScanSettings.HiddenNetwork(config.SSID));
5522            }
5523            // Call wifi native to start the scan
5524            if (startScanNative(freqs, hiddenNetworks, WIFI_WORK_SOURCE)) {
5525                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
5526            } else {
5527                // used for debug only, mark scan as failed
5528                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
5529            }
5530            return true;
5531        } else {
5532            if (mVerboseLoggingEnabled) logd("no channels for " + config.configKey());
5533            return false;
5534        }
5535    }
5536
5537    class L2ConnectedState extends State {
5538        @Override
5539        public void enter() {
5540            mRssiPollToken++;
5541            if (mEnableRssiPolling) {
5542                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
5543            }
5544            if (mNetworkAgent != null) {
5545                loge("Have NetworkAgent when entering L2Connected");
5546                setNetworkDetailedState(DetailedState.DISCONNECTED);
5547            }
5548            setNetworkDetailedState(DetailedState.CONNECTING);
5549
5550            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
5551                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
5552                    mLinkProperties, 60, mNetworkMisc);
5553
5554            // We must clear the config BSSID, as the wifi chipset may decide to roam
5555            // from this point on and having the BSSID specified in the network block would
5556            // cause the roam to faile and the device to disconnect
5557            clearTargetBssid("L2ConnectedState");
5558            mCountryCode.setReadyForChange(false);
5559            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
5560        }
5561
5562        @Override
5563        public void exit() {
5564            mIpManager.stop();
5565
5566            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
5567            // Bug: 15347363
5568            // For paranoia's sake, call handleNetworkDisconnect
5569            // only if BSSID is null or last networkId
5570            // is not invalid.
5571            if (mVerboseLoggingEnabled) {
5572                StringBuilder sb = new StringBuilder();
5573                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
5574                if (mLastBssid !=null) {
5575                    sb.append(" ").append(mLastBssid);
5576                }
5577            }
5578            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5579                handleNetworkDisconnect();
5580            }
5581            mCountryCode.setReadyForChange(true);
5582            mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
5583        }
5584
5585        @Override
5586        public boolean processMessage(Message message) {
5587            logStateAndMessage(message, this);
5588
5589            switch (message.what) {
5590                case DhcpClient.CMD_PRE_DHCP_ACTION:
5591                    handlePreDhcpSetup();
5592                    break;
5593                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
5594                    mIpManager.completedPreDhcpAction();
5595                    break;
5596                case DhcpClient.CMD_POST_DHCP_ACTION:
5597                    handlePostDhcpSetup();
5598                    // We advance to mConnectedState because IpManager will also send a
5599                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
5600                    // which calls updateLinkProperties, which then sends
5601                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
5602                    //
5603                    // In the event of failure, we transition to mDisconnectingState
5604                    // similarly--via messages sent back from IpManager.
5605                    break;
5606                case CMD_IPV4_PROVISIONING_SUCCESS: {
5607                    handleIPv4Success((DhcpResults) message.obj);
5608                    sendNetworkStateChangeBroadcast(mLastBssid);
5609                    break;
5610                }
5611                case CMD_IPV4_PROVISIONING_FAILURE: {
5612                    handleIPv4Failure();
5613                    break;
5614                }
5615                case CMD_IP_CONFIGURATION_SUCCESSFUL:
5616                    handleSuccessfulIpConfiguration();
5617                    reportConnectionAttemptEnd(
5618                            WifiMetrics.ConnectionEvent.FAILURE_NONE,
5619                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5620                    sendConnectedState();
5621                    transitionTo(mConnectedState);
5622                    break;
5623                case CMD_IP_CONFIGURATION_LOST:
5624                    // Get Link layer stats so that we get fresh tx packet counters.
5625                    getWifiLinkLayerStats();
5626                    handleIpConfigurationLost();
5627                    reportConnectionAttemptEnd(
5628                            WifiMetrics.ConnectionEvent.FAILURE_DHCP,
5629                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5630                    transitionTo(mDisconnectingState);
5631                    break;
5632                case CMD_IP_REACHABILITY_LOST:
5633                    if (mVerboseLoggingEnabled && message.obj != null) log((String) message.obj);
5634                    if (mIpReachabilityDisconnectEnabled) {
5635                        handleIpReachabilityLost();
5636                        transitionTo(mDisconnectingState);
5637                    } else {
5638                        logd("CMD_IP_REACHABILITY_LOST but disconnect disabled -- ignore");
5639                    }
5640                    break;
5641                case CMD_DISCONNECT:
5642                    mWifiNative.disconnect();
5643                    transitionTo(mDisconnectingState);
5644                    break;
5645                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5646                    if (message.arg1 == 1) {
5647                        mWifiNative.disconnect();
5648                        mTemporarilyDisconnectWifi = true;
5649                        transitionTo(mDisconnectingState);
5650                    }
5651                    break;
5652                case CMD_SET_OPERATIONAL_MODE:
5653                    if (message.arg1 != CONNECT_MODE) {
5654                        sendMessage(CMD_DISCONNECT);
5655                        deferMessage(message);
5656                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE ||
5657                                message.arg1 == DISABLED_MODE) {
5658                            noteWifiDisabledWhileAssociated();
5659                        }
5660                    }
5661                    break;
5662                    /* Ignore connection to same network */
5663                case WifiManager.CONNECT_NETWORK:
5664                    int netId = message.arg1;
5665                    if (mWifiInfo.getNetworkId() == netId) {
5666                        break;
5667                    }
5668                    return NOT_HANDLED;
5669                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5670                    mWifiInfo.setBSSID((String) message.obj);
5671                    mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
5672                    mWifiInfo.setNetworkId(mLastNetworkId);
5673                    if(!mLastBssid.equals(message.obj)) {
5674                        mLastBssid = (String) message.obj;
5675                        sendNetworkStateChangeBroadcast(mLastBssid);
5676                    }
5677                    break;
5678                case CMD_RSSI_POLL:
5679                    if (message.arg1 == mRssiPollToken) {
5680                        if (mEnableChipWakeUpWhenAssociated) {
5681                            if (mVerboseLoggingEnabled) {
5682                                log(" get link layer stats " + mWifiLinkLayerStatsSupported);
5683                            }
5684                            WifiLinkLayerStats stats = getWifiLinkLayerStats();
5685                            if (stats != null) {
5686                                // Sanity check the results provided by driver
5687                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
5688                                        && (stats.rssi_mgmt == 0
5689                                        || stats.beacon_rx == 0)) {
5690                                    stats = null;
5691                                }
5692                            }
5693                            // Get Info and continue polling
5694                            fetchRssiLinkSpeedAndFrequencyNative();
5695                            // Send the update score to network agent.
5696                            mWifiScoreReport.calculateAndReportScore(
5697                                    mWifiInfo, mNetworkAgent, mAggressiveHandover,
5698                                    mWifiMetrics);
5699                        }
5700                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
5701                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
5702                        if (mVerboseLoggingEnabled) sendRssiChangeBroadcast(mWifiInfo.getRssi());
5703                    } else {
5704                        // Polling has completed
5705                    }
5706                    break;
5707                case CMD_ENABLE_RSSI_POLL:
5708                    cleanWifiScore();
5709                    if (mEnableRssiPollWhenAssociated) {
5710                        mEnableRssiPolling = (message.arg1 == 1);
5711                    } else {
5712                        mEnableRssiPolling = false;
5713                    }
5714                    mRssiPollToken++;
5715                    if (mEnableRssiPolling) {
5716                        // First poll
5717                        fetchRssiLinkSpeedAndFrequencyNative();
5718                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
5719                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
5720                    }
5721                    break;
5722                case WifiManager.RSSI_PKTCNT_FETCH:
5723                    RssiPacketCountInfo info = new RssiPacketCountInfo();
5724                    fetchRssiLinkSpeedAndFrequencyNative();
5725                    info.rssi = mWifiInfo.getRssi();
5726                    fetchPktcntNative(info);
5727                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
5728                    break;
5729                case CMD_DELAYED_NETWORK_DISCONNECT:
5730                    if (!isLinkDebouncing()) {
5731
5732                        // Ignore if we are not debouncing
5733                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
5734                                + message.arg1);
5735                        return HANDLED;
5736                    } else {
5737                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
5738                                + message.arg1);
5739
5740                        mIsLinkDebouncing = false;
5741                        // If we are still debouncing while this message comes,
5742                        // it means we were not able to reconnect within the alloted time
5743                        // = LINK_FLAPPING_DEBOUNCE_MSEC
5744                        // and thus, trigger a real disconnect
5745                        handleNetworkDisconnect();
5746                        transitionTo(mDisconnectedState);
5747                    }
5748                    break;
5749                case CMD_ASSOCIATED_BSSID:
5750                    if ((String) message.obj == null) {
5751                        logw("Associated command w/o BSSID");
5752                        break;
5753                    }
5754                    mLastBssid = (String) message.obj;
5755                    if (mLastBssid != null && (mWifiInfo.getBSSID() == null
5756                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
5757                        mWifiInfo.setBSSID((String) message.obj);
5758                        sendNetworkStateChangeBroadcast(mLastBssid);
5759                    }
5760                    break;
5761                case CMD_START_RSSI_MONITORING_OFFLOAD:
5762                case CMD_RSSI_THRESHOLD_BREACH:
5763                    byte currRssi = (byte) message.arg1;
5764                    processRssiThreshold(currRssi, message.what);
5765                    break;
5766                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
5767                    stopRssiMonitoringOffload();
5768                    break;
5769                case CMD_RESET_SIM_NETWORKS:
5770                    if (message.arg1 == 0 // sim was removed
5771                            && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
5772                        WifiConfiguration config =
5773                                mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
5774                        if (TelephonyUtil.isSimConfig(config)) {
5775                            mWifiNative.disconnect();
5776                            transitionTo(mDisconnectingState);
5777                        }
5778                    }
5779                    /* allow parent state to reset data for other networks */
5780                    return NOT_HANDLED;
5781                default:
5782                    return NOT_HANDLED;
5783            }
5784
5785            return HANDLED;
5786        }
5787    }
5788
5789    class ObtainingIpState extends State {
5790        @Override
5791        public void enter() {
5792            WifiConfiguration currentConfig = getCurrentWifiConfiguration();
5793            boolean isUsingStaticIp =
5794                    (currentConfig.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
5795            if (mVerboseLoggingEnabled) {
5796                String key = "";
5797                if (getCurrentWifiConfiguration() != null) {
5798                    key = getCurrentWifiConfiguration().configKey();
5799                }
5800                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
5801                        + " " + key + " "
5802                        + " roam=" + mAutoRoaming
5803                        + " static=" + isUsingStaticIp);
5804            }
5805
5806            // Reset link Debouncing, indicating we have successfully re-connected to the AP
5807            // We might still be roaming
5808            mIsLinkDebouncing = false;
5809
5810            // Send event to CM & network change broadcast
5811            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
5812
5813            // We must clear the config BSSID, as the wifi chipset may decide to roam
5814            // from this point on and having the BSSID specified in the network block would
5815            // cause the roam to fail and the device to disconnect.
5816            clearTargetBssid("ObtainingIpAddress");
5817
5818            // Stop IpManager in case we're switching from DHCP to static
5819            // configuration or vice versa.
5820            //
5821            // TODO: Only ever enter this state the first time we connect to a
5822            // network, never on switching between static configuration and
5823            // DHCP. When we transition from static configuration to DHCP in
5824            // particular, we must tell ConnectivityService that we're
5825            // disconnected, because DHCP might take a long time during which
5826            // connectivity APIs such as getActiveNetworkInfo should not return
5827            // CONNECTED.
5828            stopIpManager();
5829
5830            mIpManager.setHttpProxy(currentConfig.getHttpProxy());
5831            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
5832                mIpManager.setTcpBufferSizes(mTcpBufferSizes);
5833            }
5834
5835            if (!isUsingStaticIp) {
5836                final IpManager.ProvisioningConfiguration prov =
5837                        IpManager.buildProvisioningConfiguration()
5838                            .withPreDhcpAction()
5839                            .withApfCapabilities(mWifiNative.getApfCapabilities())
5840                            .build();
5841                mIpManager.startProvisioning(prov);
5842                // Get Link layer stats so as we get fresh tx packet counters
5843                getWifiLinkLayerStats();
5844            } else {
5845                StaticIpConfiguration config = currentConfig.getStaticIpConfiguration();
5846                if (config.ipAddress == null) {
5847                    logd("Static IP lacks address");
5848                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
5849                } else {
5850                    final IpManager.ProvisioningConfiguration prov =
5851                            IpManager.buildProvisioningConfiguration()
5852                                .withStaticConfiguration(config)
5853                                .withApfCapabilities(mWifiNative.getApfCapabilities())
5854                                .build();
5855                    mIpManager.startProvisioning(prov);
5856                }
5857            }
5858        }
5859
5860        @Override
5861        public boolean processMessage(Message message) {
5862            logStateAndMessage(message, this);
5863
5864            switch(message.what) {
5865                case CMD_START_CONNECT:
5866                case CMD_START_ROAM:
5867                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5868                    break;
5869                case WifiManager.SAVE_NETWORK:
5870                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5871                    deferMessage(message);
5872                    break;
5873                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5874                    reportConnectionAttemptEnd(
5875                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
5876                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
5877                    return NOT_HANDLED;
5878                case CMD_SET_HIGH_PERF_MODE:
5879                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5880                    deferMessage(message);
5881                    break;
5882                    /* Defer scan request since we should not switch to other channels at DHCP */
5883                case CMD_START_SCAN:
5884                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5885                    deferMessage(message);
5886                    break;
5887                default:
5888                    return NOT_HANDLED;
5889            }
5890            return HANDLED;
5891        }
5892    }
5893
5894    private void sendConnectedState() {
5895        // If this network was explicitly selected by the user, evaluate whether to call
5896        // explicitlySelected() so the system can treat it appropriately.
5897        WifiConfiguration config = getCurrentWifiConfiguration();
5898        if (mWifiConfigManager.getLastSelectedNetwork() == config.networkId) {
5899            boolean prompt =
5900                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
5901            if (mVerboseLoggingEnabled) {
5902                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
5903            }
5904            if (prompt) {
5905                // Selected by the user via Settings or QuickSettings. If this network has Internet
5906                // access, switch to it. Otherwise, switch to it only if the user confirms that they
5907                // really want to switch, or has already confirmed and selected "Don't ask again".
5908                if (mVerboseLoggingEnabled) {
5909                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
5910                }
5911                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
5912            }
5913        }
5914
5915        setNetworkDetailedState(DetailedState.CONNECTED);
5916        mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId);
5917        sendNetworkStateChangeBroadcast(mLastBssid);
5918    }
5919
5920    class RoamingState extends State {
5921        boolean mAssociated;
5922        @Override
5923        public void enter() {
5924            if (mVerboseLoggingEnabled) {
5925                log("RoamingState Enter"
5926                        + " mScreenOn=" + mScreenOn );
5927            }
5928
5929            // Make sure we disconnect if roaming fails
5930            roamWatchdogCount++;
5931            logd("Start Roam Watchdog " + roamWatchdogCount);
5932            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
5933                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
5934            mAssociated = false;
5935        }
5936        @Override
5937        public boolean processMessage(Message message) {
5938            logStateAndMessage(message, this);
5939            WifiConfiguration config;
5940            switch (message.what) {
5941                case CMD_IP_CONFIGURATION_LOST:
5942                    config = getCurrentWifiConfiguration();
5943                    if (config != null) {
5944                        mWifiDiagnostics.captureBugReportData(
5945                                WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
5946                    }
5947                    return NOT_HANDLED;
5948                case CMD_UNWANTED_NETWORK:
5949                    if (mVerboseLoggingEnabled) {
5950                        log("Roaming and CS doesnt want the network -> ignore");
5951                    }
5952                    return HANDLED;
5953                case CMD_SET_OPERATIONAL_MODE:
5954                    if (message.arg1 != CONNECT_MODE) {
5955                        deferMessage(message);
5956                    }
5957                    break;
5958                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5959                    /**
5960                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
5961                     * before NETWORK_DISCONNECTION_EVENT
5962                     * And there is an associated BSSID corresponding to our target BSSID, then
5963                     * we have missed the network disconnection, transition to mDisconnectedState
5964                     * and handle the rest of the events there.
5965                     */
5966                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
5967                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
5968                            || stateChangeResult.state == SupplicantState.INACTIVE
5969                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
5970                        if (mVerboseLoggingEnabled) {
5971                            log("STATE_CHANGE_EVENT in roaming state "
5972                                    + stateChangeResult.toString() );
5973                        }
5974                        if (stateChangeResult.BSSID != null
5975                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
5976                            handleNetworkDisconnect();
5977                            transitionTo(mDisconnectedState);
5978                        }
5979                    }
5980                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
5981                        // We completed the layer2 roaming part
5982                        mAssociated = true;
5983                        if (stateChangeResult.BSSID != null) {
5984                            mTargetRoamBSSID = stateChangeResult.BSSID;
5985                        }
5986                    }
5987                    break;
5988                case CMD_ROAM_WATCHDOG_TIMER:
5989                    if (roamWatchdogCount == message.arg1) {
5990                        if (mVerboseLoggingEnabled) log("roaming watchdog! -> disconnect");
5991                        mWifiMetrics.endConnectionEvent(
5992                                WifiMetrics.ConnectionEvent.FAILURE_ROAM_TIMEOUT,
5993                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
5994                        mRoamFailCount++;
5995                        handleNetworkDisconnect();
5996                        mWifiNative.disconnect();
5997                        transitionTo(mDisconnectedState);
5998                    }
5999                    break;
6000                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6001                    if (mAssociated) {
6002                        if (mVerboseLoggingEnabled) {
6003                            log("roaming and Network connection established");
6004                        }
6005                        mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
6006                        mLastBssid = (String) message.obj;
6007                        mWifiInfo.setBSSID(mLastBssid);
6008                        mWifiInfo.setNetworkId(mLastNetworkId);
6009                        mWifiConnectivityManager.trackBssid(mLastBssid, true);
6010                        sendNetworkStateChangeBroadcast(mLastBssid);
6011
6012                        // Successful framework roam! (probably)
6013                        reportConnectionAttemptEnd(
6014                                WifiMetrics.ConnectionEvent.FAILURE_NONE,
6015                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6016
6017                        // We must clear the config BSSID, as the wifi chipset may decide to roam
6018                        // from this point on and having the BSSID specified by QNS would cause
6019                        // the roam to fail and the device to disconnect.
6020                        // When transition from RoamingState to DisconnectingState or
6021                        // DisconnectedState, the config BSSID is cleared by
6022                        // handleNetworkDisconnect().
6023                        clearTargetBssid("RoamingCompleted");
6024
6025                        // We used to transition to ObtainingIpState in an
6026                        // attempt to do DHCPv4 RENEWs on framework roams.
6027                        // DHCP can take too long to time out, and we now rely
6028                        // upon IpManager's use of IpReachabilityMonitor to
6029                        // confirm our current network configuration.
6030                        //
6031                        // mIpManager.confirmConfiguration() is called within
6032                        // the handling of SupplicantState.COMPLETED.
6033                        transitionTo(mConnectedState);
6034                    } else {
6035                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6036                    }
6037                    break;
6038                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6039                    // Throw away but only if it corresponds to the network we're roaming to
6040                    String bssid = (String) message.obj;
6041                    if (true) {
6042                        String target = "";
6043                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
6044                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
6045                                + " BSSID=" + bssid
6046                                + " target=" + target);
6047                    }
6048                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
6049                        handleNetworkDisconnect();
6050                        transitionTo(mDisconnectedState);
6051                    }
6052                    break;
6053                case WifiMonitor.SSID_TEMP_DISABLED:
6054                    // Auth error while roaming
6055                    int netId = lookupFrameworkNetworkId(message.arg1);
6056                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
6057                            + " id=" + netId
6058                            + " isRoaming=" + isRoaming()
6059                            + " roam=" + mAutoRoaming);
6060                    if (netId == mLastNetworkId) {
6061                        config = getCurrentWifiConfiguration();
6062                        if (config != null) {
6063                            mWifiDiagnostics.captureBugReportData(
6064                                    WifiDiagnostics.REPORT_REASON_AUTOROAM_FAILURE);
6065                        }
6066                        handleNetworkDisconnect();
6067                        transitionTo(mDisconnectingState);
6068                    }
6069                    return NOT_HANDLED;
6070                case CMD_START_SCAN:
6071                    deferMessage(message);
6072                    break;
6073                default:
6074                    return NOT_HANDLED;
6075            }
6076            return HANDLED;
6077        }
6078
6079        @Override
6080        public void exit() {
6081            logd("WifiStateMachine: Leaving Roaming state");
6082        }
6083    }
6084
6085    class ConnectedState extends State {
6086        @Override
6087        public void enter() {
6088            updateDefaultRouteMacAddress(1000);
6089            if (mVerboseLoggingEnabled) {
6090                log("Enter ConnectedState "
6091                       + " mScreenOn=" + mScreenOn);
6092            }
6093
6094            mWifiConnectivityManager.handleConnectionStateChanged(
6095                    WifiConnectivityManager.WIFI_STATE_CONNECTED);
6096            registerConnected();
6097            lastConnectAttemptTimestamp = 0;
6098            targetWificonfiguration = null;
6099            // Paranoia
6100            mIsLinkDebouncing = false;
6101
6102            // Not roaming anymore
6103            mAutoRoaming = false;
6104
6105            if (testNetworkDisconnect) {
6106                testNetworkDisconnectCounter++;
6107                logd("ConnectedState Enter start disconnect test " +
6108                        testNetworkDisconnectCounter);
6109                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
6110                        testNetworkDisconnectCounter, 0), 15000);
6111            }
6112
6113            mLastDriverRoamAttempt = 0;
6114            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
6115            mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
6116        }
6117        @Override
6118        public boolean processMessage(Message message) {
6119            WifiConfiguration config = null;
6120            logStateAndMessage(message, this);
6121
6122            switch (message.what) {
6123                case CMD_UNWANTED_NETWORK:
6124                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
6125                        mWifiNative.disconnect();
6126                        transitionTo(mDisconnectingState);
6127                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
6128                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
6129                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
6130                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
6131                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
6132                        config = getCurrentWifiConfiguration();
6133                        if (config != null) {
6134                            // Disable autojoin
6135                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
6136                                mWifiConfigManager.setNetworkValidatedInternetAccess(
6137                                        config.networkId, false);
6138                                mWifiConfigManager.updateNetworkSelectionStatus(config.networkId,
6139                                        WifiConfiguration.NetworkSelectionStatus
6140                                        .DISABLED_NO_INTERNET);
6141                            }
6142                            mWifiConfigManager.incrementNetworkNoInternetAccessReports(
6143                                    config.networkId);
6144                        }
6145                    }
6146                    return HANDLED;
6147                case CMD_NETWORK_STATUS:
6148                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
6149                        config = getCurrentWifiConfiguration();
6150                        if (config != null) {
6151                            // re-enable autojoin
6152                            mWifiConfigManager.setNetworkValidatedInternetAccess(
6153                                    config.networkId, true);
6154                        }
6155                    }
6156                    return HANDLED;
6157                case CMD_ACCEPT_UNVALIDATED:
6158                    boolean accept = (message.arg1 != 0);
6159                    mWifiConfigManager.setNetworkNoInternetAccessExpected(mLastNetworkId, accept);
6160                    return HANDLED;
6161                case CMD_TEST_NETWORK_DISCONNECT:
6162                    // Force a disconnect
6163                    if (message.arg1 == testNetworkDisconnectCounter) {
6164                        mWifiNative.disconnect();
6165                    }
6166                    break;
6167                case CMD_ASSOCIATED_BSSID:
6168                    // ASSOCIATING to a new BSSID while already connected, indicates
6169                    // that driver is roaming
6170                    mLastDriverRoamAttempt = mClock.getWallClockMillis();
6171                    return NOT_HANDLED;
6172                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6173                    long lastRoam = 0;
6174                    reportConnectionAttemptEnd(
6175                            WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
6176                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6177                    if (mLastDriverRoamAttempt != 0) {
6178                        // Calculate time since last driver roam attempt
6179                        lastRoam = mClock.getWallClockMillis() - mLastDriverRoamAttempt;
6180                        mLastDriverRoamAttempt = 0;
6181                    }
6182                    if (unexpectedDisconnectedReason(message.arg2)) {
6183                        mWifiDiagnostics.captureBugReportData(
6184                                WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
6185                    }
6186                    config = getCurrentWifiConfiguration();
6187                    if (mEnableLinkDebouncing
6188                            && mScreenOn
6189                            && !isLinkDebouncing()
6190                            && config != null
6191                            && config.getNetworkSelectionStatus().isNetworkEnabled()
6192                            && config.networkId != mWifiConfigManager.getLastSelectedNetwork()
6193                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
6194                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
6195                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
6196                                    && mWifiInfo.getRssi() >
6197                                     mThresholdQualifiedRssi5)
6198                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
6199                                    && mWifiInfo.getRssi() >
6200                                    mThresholdQualifiedRssi5))) {
6201                        // Start de-bouncing the L2 disconnection:
6202                        // this L2 disconnection might be spurious.
6203                        // Hence we allow 4 seconds for the state machine to try
6204                        // to reconnect, go thru the
6205                        // roaming cycle and enter Obtaining IP address
6206                        // before signalling the disconnect to ConnectivityService and L3
6207                        startScanForConfiguration(getCurrentWifiConfiguration());
6208                        mIsLinkDebouncing = true;
6209
6210                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
6211                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
6212                        if (mVerboseLoggingEnabled) {
6213                            log("NETWORK_DISCONNECTION_EVENT in connected state"
6214                                    + " BSSID=" + mWifiInfo.getBSSID()
6215                                    + " RSSI=" + mWifiInfo.getRssi()
6216                                    + " freq=" + mWifiInfo.getFrequency()
6217                                    + " reason=" + message.arg2
6218                                    + " -> debounce");
6219                        }
6220                        return HANDLED;
6221                    } else {
6222                        if (mVerboseLoggingEnabled) {
6223                            log("NETWORK_DISCONNECTION_EVENT in connected state"
6224                                    + " BSSID=" + mWifiInfo.getBSSID()
6225                                    + " RSSI=" + mWifiInfo.getRssi()
6226                                    + " freq=" + mWifiInfo.getFrequency()
6227                                    + " was debouncing=" + isLinkDebouncing()
6228                                    + " reason=" + message.arg2
6229                                    + " Network Selection Status=" + (config == null ? "Unavailable"
6230                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
6231                        }
6232                    }
6233                    break;
6234                case CMD_START_ROAM:
6235                    // Clear the driver roam indication since we are attempting a framework roam
6236                    mLastDriverRoamAttempt = 0;
6237
6238                    /* Connect command coming from auto-join */
6239                    int netId = message.arg1;
6240                    ScanResult candidate = (ScanResult)message.obj;
6241                    String bssid = SUPPLICANT_BSSID_ANY;
6242                    if (candidate != null) {
6243                        bssid = candidate.BSSID;
6244                    }
6245                    config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
6246                    if (config == null) {
6247                        loge("CMD_START_ROAM and no config, bail out...");
6248                        break;
6249                    }
6250
6251                    setTargetBssid(config, bssid);
6252                    mTargetNetworkId = netId;
6253
6254                    logd("CMD_START_ROAM sup state "
6255                            + mSupplicantStateTracker.getSupplicantStateName()
6256                            + " my state " + getCurrentState().getName()
6257                            + " nid=" + Integer.toString(netId)
6258                            + " config " + config.configKey()
6259                            + " targetRoamBSSID " + mTargetRoamBSSID);
6260
6261                    mWifiMetrics.startConnectionEvent(config, mTargetRoamBSSID,
6262                            WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
6263                    if (mWifiSupplicantControl.roamToNetwork(config)) {
6264                        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
6265                        targetWificonfiguration = config;
6266                        mAutoRoaming = true;
6267                        transitionTo(mRoamingState);
6268                    } else {
6269                        loge("CMD_START_ROAM Failed to start roaming to network " + config);
6270                        reportConnectionAttemptEnd(
6271                                WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
6272                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
6273                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6274                                WifiManager.ERROR);
6275                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6276                        break;
6277                    }
6278                    break;
6279                case CMD_START_IP_PACKET_OFFLOAD: {
6280                        int slot = message.arg1;
6281                        int intervalSeconds = message.arg2;
6282                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
6283                        byte[] dstMac;
6284                        try {
6285                            InetAddress gateway = RouteInfo.selectBestRoute(
6286                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
6287                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
6288                            dstMac = macAddressFromString(dstMacStr);
6289                        } catch (NullPointerException|IllegalArgumentException e) {
6290                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
6291                            mNetworkAgent.onPacketKeepaliveEvent(slot,
6292                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
6293                            break;
6294                        }
6295                        pkt.dstMac = dstMac;
6296                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
6297                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
6298                        break;
6299                    }
6300                default:
6301                    return NOT_HANDLED;
6302            }
6303            return HANDLED;
6304        }
6305
6306        @Override
6307        public void exit() {
6308            logd("WifiStateMachine: Leaving Connected state");
6309            mWifiConnectivityManager.handleConnectionStateChanged(
6310                     WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
6311
6312            mLastDriverRoamAttempt = 0;
6313            mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
6314        }
6315    }
6316
6317    class DisconnectingState extends State {
6318
6319        @Override
6320        public void enter() {
6321
6322            if (mVerboseLoggingEnabled) {
6323                logd(" Enter DisconnectingState State screenOn=" + mScreenOn);
6324            }
6325
6326            // Make sure we disconnect: we enter this state prior to connecting to a new
6327            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
6328            // event which in this case will be indicating that supplicant started to associate.
6329            // In some cases supplicant doesn't ignore the connect requests (it might not
6330            // find the target SSID in its cache),
6331            // Therefore we end up stuck that state, hence the need for the watchdog.
6332            disconnectingWatchdogCount++;
6333            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
6334            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
6335                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
6336        }
6337
6338        @Override
6339        public boolean processMessage(Message message) {
6340            logStateAndMessage(message, this);
6341            switch (message.what) {
6342                case CMD_SET_OPERATIONAL_MODE:
6343                    if (message.arg1 != CONNECT_MODE) {
6344                        deferMessage(message);
6345                    }
6346                    break;
6347                case CMD_START_SCAN:
6348                    deferMessage(message);
6349                    return HANDLED;
6350                case CMD_DISCONNECT:
6351                    if (mVerboseLoggingEnabled) log("Ignore CMD_DISCONNECT when already disconnecting.");
6352                    break;
6353                case CMD_DISCONNECTING_WATCHDOG_TIMER:
6354                    if (disconnectingWatchdogCount == message.arg1) {
6355                        if (mVerboseLoggingEnabled) log("disconnecting watchdog! -> disconnect");
6356                        handleNetworkDisconnect();
6357                        transitionTo(mDisconnectedState);
6358                    }
6359                    break;
6360                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6361                    /**
6362                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
6363                     * we have missed the network disconnection, transition to mDisconnectedState
6364                     * and handle the rest of the events there
6365                     */
6366                    deferMessage(message);
6367                    handleNetworkDisconnect();
6368                    transitionTo(mDisconnectedState);
6369                    break;
6370                default:
6371                    return NOT_HANDLED;
6372            }
6373            return HANDLED;
6374        }
6375    }
6376
6377    class DisconnectedState extends State {
6378        @Override
6379        public void enter() {
6380            // We dont scan frequently if this is a temporary disconnect
6381            // due to p2p
6382            if (mTemporarilyDisconnectWifi) {
6383                p2pSendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
6384                return;
6385            }
6386
6387            if (mVerboseLoggingEnabled) {
6388                logd(" Enter DisconnectedState screenOn=" + mScreenOn);
6389            }
6390
6391            /** clear the roaming state, if we were roaming, we failed */
6392            mAutoRoaming = false;
6393
6394            mWifiConnectivityManager.handleConnectionStateChanged(
6395                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
6396
6397            /**
6398             * If we have no networks saved, the supplicant stops doing the periodic scan.
6399             * The scans are useful to notify the user of the presence of an open network.
6400             * Note that these are not wake up scans.
6401             */
6402            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
6403                    && mWifiConfigManager.getSavedNetworks().size() == 0) {
6404                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6405                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6406            }
6407
6408            mDisconnectedTimeStamp = mClock.getWallClockMillis();
6409        }
6410        @Override
6411        public boolean processMessage(Message message) {
6412            boolean ret = HANDLED;
6413
6414            logStateAndMessage(message, this);
6415
6416            switch (message.what) {
6417                case CMD_NO_NETWORKS_PERIODIC_SCAN:
6418                    if (mP2pConnected.get()) break;
6419                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
6420                            mWifiConfigManager.getSavedNetworks().size() == 0) {
6421                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, WIFI_WORK_SOURCE);
6422                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6423                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6424                    }
6425                    break;
6426                case WifiManager.FORGET_NETWORK:
6427                case CMD_REMOVE_NETWORK:
6428                case CMD_REMOVE_APP_CONFIGURATIONS:
6429                case CMD_REMOVE_USER_CONFIGURATIONS:
6430                    // Set up a delayed message here. After the forget/remove is handled
6431                    // the handled delayed message will determine if there is a need to
6432                    // scan and continue
6433                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6434                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6435                    ret = NOT_HANDLED;
6436                    break;
6437                case CMD_SET_OPERATIONAL_MODE:
6438                    if (message.arg1 != CONNECT_MODE) {
6439                        mOperationalMode = message.arg1;
6440                        if (mOperationalMode == DISABLED_MODE) {
6441                            transitionTo(mSupplicantStoppingState);
6442                        } else if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6443                            p2pSendMessage(CMD_DISABLE_P2P_REQ);
6444                            setWifiState(WIFI_STATE_DISABLED);
6445                            transitionTo(mScanModeState);
6446                        } else if (mOperationalMode == SCAN_ONLY_MODE) {
6447                            transitionTo(mScanModeState);
6448                        }
6449                    }
6450                    break;
6451                case CMD_DISCONNECT:
6452                    mWifiNative.disconnect();
6453                    break;
6454                /* Ignore network disconnect */
6455                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6456                    // Interpret this as an L2 connection failure
6457                    break;
6458                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6459                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6460                    if (mVerboseLoggingEnabled) {
6461                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
6462                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
6463                                + " debouncing=" + isLinkDebouncing());
6464                    }
6465                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
6466                    /* ConnectModeState does the rest of the handling */
6467                    ret = NOT_HANDLED;
6468                    break;
6469                case CMD_START_SCAN:
6470                    if (!checkOrDeferScanAllowed(message)) {
6471                        // The scan request was rescheduled
6472                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
6473                        return HANDLED;
6474                    }
6475
6476                    ret = NOT_HANDLED;
6477                    break;
6478                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
6479                    NetworkInfo info = (NetworkInfo) message.obj;
6480                    mP2pConnected.set(info.isConnected());
6481                    if (mP2pConnected.get()) {
6482                        int defaultInterval = mContext.getResources().getInteger(
6483                                R.integer.config_wifi_scan_interval_p2p_connected);
6484                        long scanIntervalMs = mFacade.getLongSetting(mContext,
6485                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
6486                                defaultInterval);
6487                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
6488                    } else if (mWifiConfigManager.getSavedNetworks().size() == 0) {
6489                        if (mVerboseLoggingEnabled) log("Turn on scanning after p2p disconnected");
6490                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
6491                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
6492                    }
6493                    break;
6494                case CMD_RECONNECT:
6495                case CMD_REASSOCIATE:
6496                    if (mTemporarilyDisconnectWifi) {
6497                        // Drop a third party reconnect/reassociate if STA is
6498                        // temporarily disconnected for p2p
6499                        break;
6500                    } else {
6501                        // ConnectModeState handles it
6502                        ret = NOT_HANDLED;
6503                    }
6504                    break;
6505                case CMD_SCREEN_STATE_CHANGED:
6506                    handleScreenStateChanged(message.arg1 != 0);
6507                    break;
6508                default:
6509                    ret = NOT_HANDLED;
6510            }
6511            return ret;
6512        }
6513
6514        @Override
6515        public void exit() {
6516            mWifiConnectivityManager.handleConnectionStateChanged(
6517                     WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
6518        }
6519    }
6520
6521    class WpsRunningState extends State {
6522        // Tracks the source to provide a reply
6523        private Message mSourceMessage;
6524        @Override
6525        public void enter() {
6526            mSourceMessage = Message.obtain(getCurrentMessage());
6527        }
6528        @Override
6529        public boolean processMessage(Message message) {
6530            logStateAndMessage(message, this);
6531
6532            switch (message.what) {
6533                case WifiMonitor.WPS_SUCCESS_EVENT:
6534                    // Ignore intermediate success, wait for full connection
6535                    break;
6536                case WifiMonitor.NETWORK_CONNECTION_EVENT:
6537                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
6538                    mSourceMessage.recycle();
6539                    mSourceMessage = null;
6540                    deferMessage(message);
6541                    transitionTo(mDisconnectedState);
6542                    break;
6543                case WifiMonitor.WPS_OVERLAP_EVENT:
6544                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
6545                            WifiManager.WPS_OVERLAP_ERROR);
6546                    mSourceMessage.recycle();
6547                    mSourceMessage = null;
6548                    transitionTo(mDisconnectedState);
6549                    break;
6550                case WifiMonitor.WPS_FAIL_EVENT:
6551                    // Arg1 has the reason for the failure
6552                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
6553                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
6554                        mSourceMessage.recycle();
6555                        mSourceMessage = null;
6556                        transitionTo(mDisconnectedState);
6557                    } else {
6558                        if (mVerboseLoggingEnabled) {
6559                            log("Ignore unspecified fail event during WPS connection");
6560                        }
6561                    }
6562                    break;
6563                case WifiMonitor.WPS_TIMEOUT_EVENT:
6564                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
6565                            WifiManager.WPS_TIMED_OUT);
6566                    mSourceMessage.recycle();
6567                    mSourceMessage = null;
6568                    transitionTo(mDisconnectedState);
6569                    break;
6570                case WifiManager.START_WPS:
6571                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
6572                    break;
6573                case WifiManager.CANCEL_WPS:
6574                    if (mWifiNative.cancelWps()) {
6575                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
6576                    } else {
6577                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
6578                    }
6579                    transitionTo(mDisconnectedState);
6580                    break;
6581                /**
6582                 * Defer all commands that can cause connections to a different network
6583                 * or put the state machine out of connect mode
6584                 */
6585                case CMD_SET_OPERATIONAL_MODE:
6586                case WifiManager.CONNECT_NETWORK:
6587                case CMD_ENABLE_NETWORK:
6588                case CMD_RECONNECT:
6589                case CMD_REASSOCIATE:
6590                    deferMessage(message);
6591                    break;
6592                case CMD_START_CONNECT:
6593                case CMD_START_ROAM:
6594                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6595                    return HANDLED;
6596                case CMD_START_SCAN:
6597                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6598                    return HANDLED;
6599                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6600                    if (mVerboseLoggingEnabled) log("Network connection lost");
6601                    handleNetworkDisconnect();
6602                    break;
6603                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6604                    if (mVerboseLoggingEnabled) {
6605                        log("Ignore Assoc reject event during WPS Connection");
6606                    }
6607                    break;
6608                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6609                    // Disregard auth failure events during WPS connection. The
6610                    // EAP sequence is retried several times, and there might be
6611                    // failures (especially for wps pin). We will get a WPS_XXX
6612                    // event at the end of the sequence anyway.
6613                    if (mVerboseLoggingEnabled) log("Ignore auth failure during WPS connection");
6614                    break;
6615                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6616                    // Throw away supplicant state changes when WPS is running.
6617                    // We will start getting supplicant state changes once we get
6618                    // a WPS success or failure
6619                    break;
6620                default:
6621                    return NOT_HANDLED;
6622            }
6623            return HANDLED;
6624        }
6625
6626        @Override
6627        public void exit() {
6628            mWifiConfigManager.loadFromStore();
6629        }
6630    }
6631
6632    class SoftApState extends State {
6633        private SoftApManager mSoftApManager;
6634
6635        private class SoftApListener implements SoftApManager.Listener {
6636            @Override
6637            public void onStateChanged(int state, int reason) {
6638                if (state == WIFI_AP_STATE_DISABLED) {
6639                    sendMessage(CMD_AP_STOPPED);
6640                } else if (state == WIFI_AP_STATE_FAILED) {
6641                    sendMessage(CMD_START_AP_FAILURE);
6642                }
6643
6644                setWifiApState(state, reason);
6645            }
6646        }
6647
6648        @Override
6649        public void enter() {
6650            final Message message = getCurrentMessage();
6651            if (message.what != CMD_START_AP) {
6652                throw new RuntimeException("Illegal transition to SoftApState: " + message);
6653            }
6654
6655            IApInterface apInterface = setupDriverForSoftAp();
6656            if (apInterface == null) {
6657                setWifiApState(WIFI_AP_STATE_FAILED,
6658                        WifiManager.SAP_START_FAILURE_GENERAL);
6659                /**
6660                 * Transition to InitialState to reset the
6661                 * driver/HAL back to the initial state.
6662                 */
6663                transitionTo(mInitialState);
6664                return;
6665            }
6666
6667            WifiConfiguration config = (WifiConfiguration) message.obj;
6668
6669            checkAndSetConnectivityInstance();
6670            mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
6671                                                             new SoftApListener(),
6672                                                             apInterface,
6673                                                             config);
6674            mSoftApManager.start();
6675        }
6676
6677        @Override
6678        public void exit() {
6679            mSoftApManager = null;
6680        }
6681
6682        @Override
6683        public boolean processMessage(Message message) {
6684            logStateAndMessage(message, this);
6685
6686            switch(message.what) {
6687                case CMD_START_AP:
6688                    /* Ignore start command when it is starting/started. */
6689                    break;
6690                case CMD_STOP_AP:
6691                    mSoftApManager.stop();
6692                    break;
6693                case CMD_START_AP_FAILURE:
6694                    transitionTo(mInitialState);
6695                    break;
6696                case CMD_AP_STOPPED:
6697                    transitionTo(mInitialState);
6698                    break;
6699                default:
6700                    return NOT_HANDLED;
6701            }
6702            return HANDLED;
6703        }
6704    }
6705
6706    /**
6707     * State machine initiated requests can have replyTo set to null indicating
6708     * there are no recepients, we ignore those reply actions.
6709     */
6710    private void replyToMessage(Message msg, int what) {
6711        if (msg.replyTo == null) return;
6712        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
6713        mReplyChannel.replyToMessage(msg, dstMsg);
6714    }
6715
6716    private void replyToMessage(Message msg, int what, int arg1) {
6717        if (msg.replyTo == null) return;
6718        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
6719        dstMsg.arg1 = arg1;
6720        mReplyChannel.replyToMessage(msg, dstMsg);
6721    }
6722
6723    private void replyToMessage(Message msg, int what, Object obj) {
6724        if (msg.replyTo == null) return;
6725        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
6726        dstMsg.obj = obj;
6727        mReplyChannel.replyToMessage(msg, dstMsg);
6728    }
6729
6730    /**
6731     * arg2 on the source message has a unique id that needs to be retained in replies
6732     * to match the request
6733     * <p>see WifiManager for details
6734     */
6735    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
6736        Message msg = Message.obtain();
6737        msg.what = what;
6738        msg.arg2 = srcMsg.arg2;
6739        return msg;
6740    }
6741
6742    /**
6743     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
6744     * @param config Must have a WifiConfiguration object to succeed
6745     */
6746    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
6747            WifiConfiguration config) {
6748        if (config != null && config.preSharedKey != null) {
6749            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
6750            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
6751            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
6752                    wifiCredentialEventType);
6753            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
6754                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
6755        }
6756    }
6757
6758    void handleGsmAuthRequest(SimAuthRequestData requestData) {
6759        if (targetWificonfiguration == null
6760                || targetWificonfiguration.networkId
6761                == lookupFrameworkNetworkId(requestData.networkId)) {
6762            logd("id matches targetWifiConfiguration");
6763        } else {
6764            logd("id does not match targetWifiConfiguration");
6765            return;
6766        }
6767
6768        String response =
6769                TelephonyUtil.getGsmSimAuthResponse(requestData.data, getTelephonyManager());
6770        if (response == null) {
6771            mWifiNative.simAuthFailedResponse(requestData.networkId);
6772        } else {
6773            logv("Supplicant Response -" + response);
6774            mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
6775        }
6776    }
6777
6778    void handle3GAuthRequest(SimAuthRequestData requestData) {
6779        if (targetWificonfiguration == null
6780                || targetWificonfiguration.networkId
6781                == lookupFrameworkNetworkId(requestData.networkId)) {
6782            logd("id matches targetWifiConfiguration");
6783        } else {
6784            logd("id does not match targetWifiConfiguration");
6785            return;
6786        }
6787
6788        SimAuthResponseData response =
6789                TelephonyUtil.get3GAuthResponse(requestData, getTelephonyManager());
6790        if (response != null) {
6791            mWifiNative.simAuthResponse(requestData.networkId, response.type, response.response);
6792        } else {
6793            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
6794        }
6795    }
6796
6797    /**
6798     * Automatically connect to the network specified
6799     *
6800     * @param networkId ID of the network to connect to
6801     * @param bssid BSSID of the network
6802     */
6803    public void startConnectToNetwork(int networkId, String bssid) {
6804        synchronized (mWifiReqCountLock) {
6805            if (hasConnectionRequests()) {
6806                sendMessage(CMD_START_CONNECT, networkId, 0, bssid);
6807            }
6808        }
6809    }
6810
6811    /**
6812     * Automatically roam to the network specified
6813     *
6814     * @param networkId ID of the network to roam to
6815     * @param scanResult scan result which identifies the network to roam to
6816     */
6817    public void startRoamToNetwork(int networkId, ScanResult scanResult) {
6818        sendMessage(CMD_START_ROAM, networkId, 0, scanResult);
6819    }
6820
6821    /**
6822     * Dynamically turn on/off WifiConnectivityManager
6823     *
6824     * @param enabled true-enable; false-disable
6825     */
6826    public void enableWifiConnectivityManager(boolean enabled) {
6827        sendMessage(CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER, enabled ? 1 : 0);
6828    }
6829
6830    /**
6831     * @param reason reason code from supplicant on network disconnected event
6832     * @return true if this is a suspicious disconnect
6833     */
6834    static boolean unexpectedDisconnectedReason(int reason) {
6835        return reason == 2              // PREV_AUTH_NOT_VALID
6836                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
6837                || reason == 7          // FRAME_FROM_NONASSOC_STA
6838                || reason == 8          // STA_HAS_LEFT
6839                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
6840                || reason == 14         // MICHAEL_MIC_FAILURE
6841                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
6842                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
6843                || reason == 18         // GROUP_CIPHER_NOT_VALID
6844                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
6845                || reason == 23         // IEEE_802_1X_AUTH_FAILED
6846                || reason == 34;        // DISASSOC_LOW_ACK
6847    }
6848
6849    /**
6850     * Update WifiMetrics before dumping
6851     */
6852    void updateWifiMetrics() {
6853        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworks().size();
6854        int numOpenNetworks = 0;
6855        int numPersonalNetworks = 0;
6856        int numEnterpriseNetworks = 0;
6857        int numNetworksAddedByUser = 0;
6858        int numNetworksAddedByApps = 0;
6859        int numHiddenNetworks = 0;
6860        int numPasspoint = 0;
6861        for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) {
6862            if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
6863                numOpenNetworks++;
6864            } else if (config.isEnterprise()) {
6865                numEnterpriseNetworks++;
6866            } else {
6867                numPersonalNetworks++;
6868            }
6869            if (config.selfAdded) {
6870                numNetworksAddedByUser++;
6871            } else {
6872                numNetworksAddedByApps++;
6873            }
6874            if (config.hiddenSSID) {
6875                numHiddenNetworks++;
6876            }
6877            if (config.isPasspoint()) {
6878                numPasspoint++;
6879            }
6880        }
6881        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
6882        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
6883        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
6884        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
6885        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
6886        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
6887        mWifiMetrics.setNumHiddenNetworks(numHiddenNetworks);
6888        mWifiMetrics.setNumPasspointNetworks(numPasspoint);
6889    }
6890
6891    private static String getLinkPropertiesSummary(LinkProperties lp) {
6892        List<String> attributes = new ArrayList<>(6);
6893        if (lp.hasIPv4Address()) {
6894            attributes.add("v4");
6895        }
6896        if (lp.hasIPv4DefaultRoute()) {
6897            attributes.add("v4r");
6898        }
6899        if (lp.hasIPv4DnsServer()) {
6900            attributes.add("v4dns");
6901        }
6902        if (lp.hasGlobalIPv6Address()) {
6903            attributes.add("v6");
6904        }
6905        if (lp.hasIPv6DefaultRoute()) {
6906            attributes.add("v6r");
6907        }
6908        if (lp.hasIPv6DnsServer()) {
6909            attributes.add("v6dns");
6910        }
6911
6912        return TextUtils.join(" ", attributes);
6913    }
6914
6915    /**
6916     * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId'
6917     * This should match the network config framework is attempting to connect to.
6918     */
6919    private String getTargetSsid() {
6920        WifiConfiguration currentConfig = mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
6921        if (currentConfig != null) {
6922            return currentConfig.SSID;
6923        }
6924        return null;
6925    }
6926
6927    private void p2pSendMessage(int what) {
6928        if (mWifiP2pChannel != null) {
6929            mWifiP2pChannel.sendMessage(what);
6930        }
6931    }
6932
6933    private void p2pSendMessage(int what, int arg1) {
6934        if (mWifiP2pChannel != null) {
6935            mWifiP2pChannel.sendMessage(what, arg1);
6936        }
6937    }
6938
6939    /**
6940     * Check if there is any connection request for WiFi network.
6941     * Note, caller of this helper function must acquire mWifiReqCountLock.
6942     */
6943    private boolean hasConnectionRequests() {
6944        return mConnectionReqCount > 0 || mUntrustedReqCount > 0;
6945    }
6946
6947    /**
6948     * Returns whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
6949     */
6950    public boolean getIpReachabilityDisconnectEnabled() {
6951        return mIpReachabilityDisconnectEnabled;
6952    }
6953
6954    /**
6955     * Sets whether CMD_IP_REACHABILITY_LOST events should trigger disconnects.
6956     */
6957    public void setIpReachabilityDisconnectEnabled(boolean enabled) {
6958        mIpReachabilityDisconnectEnabled = enabled;
6959    }
6960}
6961