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