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