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