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