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