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 /**
29  * TODO:
30  * Deprecate WIFI_STATE_UNKNOWN
31  */
32 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
33 
34 import android.Manifest;
35 import android.app.ActivityManager;
36 import android.app.AlarmManager;
37 import android.app.PendingIntent;
38 import android.app.backup.IBackupManager;
39 import android.bluetooth.BluetoothAdapter;
40 import android.content.BroadcastReceiver;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.content.pm.ApplicationInfo;
45 import android.content.pm.IPackageManager;
46 import android.content.pm.PackageManager;
47 import android.database.ContentObserver;
48 import android.net.ConnectivityManager;
49 import android.net.DhcpResults;
50 import android.net.BaseDhcpStateMachine;
51 import android.net.DhcpStateMachine;
52 import android.net.Network;
53 import android.net.dhcp.DhcpClient;
54 import android.net.InterfaceConfiguration;
55 import android.net.IpReachabilityMonitor;
56 import android.net.LinkAddress;
57 import android.net.LinkProperties;
58 import android.net.NetworkAgent;
59 import android.net.NetworkCapabilities;
60 import android.net.NetworkFactory;
61 import android.net.NetworkInfo;
62 import android.net.NetworkInfo.DetailedState;
63 import android.net.NetworkRequest;
64 import android.net.NetworkUtils;
65 import android.net.RouteInfo;
66 import android.net.StaticIpConfiguration;
67 import android.net.TrafficStats;
68 import android.net.wifi.RssiPacketCountInfo;
69 import android.net.wifi.ScanResult;
70 import android.net.wifi.ScanSettings;
71 import android.net.wifi.SupplicantState;
72 import android.net.wifi.WifiChannel;
73 import android.net.wifi.WifiConfiguration;
74 import android.net.wifi.WifiConnectionStatistics;
75 import android.net.wifi.WifiEnterpriseConfig;
76 import android.net.wifi.WifiInfo;
77 import android.net.wifi.WifiLinkLayerStats;
78 import android.net.wifi.WifiManager;
79 import android.net.wifi.WifiScanner;
80 import android.net.wifi.WifiSsid;
81 import android.net.wifi.WpsInfo;
82 import android.net.wifi.WpsResult;
83 import android.net.wifi.WpsResult.Status;
84 import android.net.wifi.p2p.IWifiP2pManager;
85 import android.os.BatteryStats;
86 import android.os.Binder;
87 import android.os.Bundle;
88 import android.os.IBinder;
89 import android.os.INetworkManagementService;
90 import android.os.Looper;
91 import android.os.Message;
92 import android.os.Messenger;
93 import android.os.PowerManager;
94 import android.os.Process;
95 import android.os.RemoteException;
96 import android.os.ServiceManager;
97 import android.os.SystemClock;
98 import android.os.SystemProperties;
99 import android.os.UserHandle;
100 import android.os.WorkSource;
101 import android.provider.Settings;
102 import android.telephony.TelephonyManager;
103 import android.text.TextUtils;
104 import android.util.Log;
105 import android.util.LruCache;
106 
107 import com.android.internal.R;
108 import com.android.internal.app.IBatteryStats;
109 import com.android.internal.util.AsyncChannel;
110 import com.android.internal.util.Protocol;
111 import com.android.internal.util.State;
112 import com.android.internal.util.StateMachine;
113 import com.android.server.net.NetlinkTracker;
114 import com.android.server.wifi.hotspot2.NetworkDetail;
115 import com.android.server.wifi.hotspot2.SupplicantBridge;
116 import com.android.server.wifi.hotspot2.Utils;
117 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
118 
119 import java.io.BufferedReader;
120 import java.io.FileDescriptor;
121 import java.io.FileNotFoundException;
122 import java.io.FileReader;
123 import java.io.IOException;
124 import java.io.PrintWriter;
125 import java.net.Inet4Address;
126 import java.net.InetAddress;
127 import java.util.ArrayList;
128 import java.util.Calendar;
129 import java.util.HashSet;
130 import java.util.LinkedList;
131 import java.util.List;
132 import java.util.Locale;
133 import java.util.Queue;
134 import java.util.Random;
135 import java.util.concurrent.atomic.AtomicBoolean;
136 import java.util.concurrent.atomic.AtomicInteger;
137 import java.util.regex.Pattern;
138 
139 /**
140  * Track the state of Wifi connectivity. All event handling is done here,
141  * and all changes in connectivity state are initiated here.
142  *
143  * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
144  * In the current implementation, we support concurrent wifi p2p and wifi operation.
145  * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
146  * handles p2p operation.
147  *
148  * @hide
149  */
150 public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler {
151 
152     private static final String NETWORKTYPE = "WIFI";
153     private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT";
154     private static boolean DBG = false;
155     private static boolean VDBG = false;
156     private static boolean VVDBG = false;
157     private static boolean USE_PAUSE_SCANS = false;
158     private static boolean mLogMessages = false;
159     private static final String TAG = "WifiStateMachine";
160 
161     private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
162 
163     private static final String GOOGLE_OUI = "DA-A1-19";
164 
165     /* temporary debug flag - best network selection development */
166     private static boolean PDBG = false;
167 
168     /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
169      * the corresponding BSSID.
170      */
171     private boolean didBlackListBSSID = false;
172 
173     /**
174      * Log with error attribute
175      *
176      * @param s is string log
177      */
loge(String s)178     protected void loge(String s) {
179         Log.e(getName(), s);
180     }
logd(String s)181     protected void logd(String s) {
182         Log.d(getName(), s);
183     }
log(String s)184     protected void log(String s) {;
185         Log.d(getName(), s);
186     }
187 
188     private WifiMonitor mWifiMonitor;
189     private WifiNative mWifiNative;
190     private WifiConfigStore mWifiConfigStore;
191     private WifiAutoJoinController mWifiAutoJoinController;
192     private INetworkManagementService mNwService;
193     private ConnectivityManager mCm;
194     private WifiLogger 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 
201     /* Scan results handling */
202     private List<ScanDetail> mScanResults = new ArrayList<>();
203     private static final Pattern scanResultPattern = Pattern.compile("\t+");
204     private static final int SCAN_RESULT_CACHE_SIZE = 160;
205     private final LruCache<NetworkDetail, ScanDetail> mScanResultCache;
206     // For debug, number of known scan results that were found as part of last scan result event,
207     // as well the number of scans results returned by the supplicant with that message
208     private int mNumScanResultsKnown;
209     private int mNumScanResultsReturned;
210 
211     private boolean mScreenOn = false;
212 
213     /* Chipset supports background scan */
214     private final boolean mBackgroundScanSupported;
215 
216     private final String mInterfaceName;
217     /* Tethering interface could be separate from wlan interface */
218     private String mTetherInterfaceName;
219 
220     private int mLastSignalLevel = -1;
221     private String mLastBssid;
222     private int mLastNetworkId; // The network Id we successfully joined
223     private boolean linkDebouncing = false;
224 
225     private boolean mHalBasedPnoDriverSupported = false;
226 
227     // Below booleans are configurations coming from the Developper Settings
228     private boolean mEnableAssociatedNetworkSwitchingInDevSettings = true;
229     private boolean mHalBasedPnoEnableInDevSettings = false;
230 
231 
232     private int mHalFeatureSet = 0;
233     private static int mPnoResultFound = 0;
234 
235     @Override
onPnoNetworkFound(ScanResult results[])236     public void onPnoNetworkFound(ScanResult results[]) {
237         if (DBG) {
238             Log.e(TAG, "onPnoNetworkFound event received num = " + results.length);
239             for (int i = 0; i < results.length; i++) {
240                 Log.e(TAG, results[i].toString());
241             }
242         }
243         sendMessage(CMD_PNO_NETWORK_FOUND, results.length, 0, results);
244     }
245 
processPnoNetworkFound(ScanResult results[])246     public void processPnoNetworkFound(ScanResult results[]) {
247         ScanSettings settings = new ScanSettings();
248         settings.channelSet = new ArrayList<WifiChannel>();
249         StringBuilder sb = new StringBuilder();
250         sb.append("");
251         for (int i=0; i<results.length; i++) {
252             WifiChannel channel = new WifiChannel();
253             channel.freqMHz = results[i].frequency;
254             settings.channelSet.add(channel);
255             sb.append(results[i].SSID).append(" ");
256         }
257 
258         stopPnoOffload();
259 
260         Log.e(TAG, "processPnoNetworkFound starting scan cnt=" + mPnoResultFound);
261         startScan(PNO_NETWORK_FOUND_SOURCE, mPnoResultFound,  settings, null);
262         mPnoResultFound ++;
263         //sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
264         int delay = 30 * 1000;
265         // reconfigure Pno after 1 minutes if we're still in disconnected state
266         sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
267                 mRestartAutoJoinOffloadCounter, " processPnoNetworkFound " + sb.toString(),
268                 (long)delay);
269         mRestartAutoJoinOffloadCounter++;
270     }
271 
registerNetworkDisabled(int netId)272     public void registerNetworkDisabled(int netId) {
273         // Restart legacy PNO and autojoin offload if needed
274         sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
275                 mRestartAutoJoinOffloadCounter, " registerNetworkDisabled " + netId);
276         mRestartAutoJoinOffloadCounter++;
277     }
278 
279     // Testing various network disconnect cases by sending lots of spurious
280     // disconnect to supplicant
281     private boolean testNetworkDisconnect = false;
282 
283     private boolean mEnableRssiPolling = false;
284     private boolean mLegacyPnoEnabled = false;
285     private int mRssiPollToken = 0;
286     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
287     * In CONNECT_MODE, the STA can scan and connect to an access point
288     * In SCAN_ONLY_MODE, the STA can only scan for access points
289     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
290     */
291     private int mOperationalMode = CONNECT_MODE;
292     private boolean mIsScanOngoing = false;
293     private boolean mIsFullScanOngoing = false;
294     private boolean mSendScanResultsBroadcast = false;
295 
296     private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>();
297     private WorkSource mScanWorkSource = null;
298     private static final int UNKNOWN_SCAN_SOURCE = -1;
299     private static final int SCAN_ALARM_SOURCE = -2;
300     private static final int ADD_OR_UPDATE_SOURCE = -3;
301     private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4;
302     private static final int ENABLE_WIFI = -5;
303     public static final int DFS_RESTRICTED_SCAN_REQUEST = -6;
304     public static final int PNO_NETWORK_FOUND_SOURCE = -7;
305 
306     private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
307     private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
308     private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
309     private static final String SCAN_REQUEST_TIME = "scan_request_time";
310 
311     /* Tracks if state machine has received any screen state change broadcast yet.
312      * We can miss one of these at boot.
313      */
314     private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false);
315 
316     private boolean mBluetoothConnectionActive = false;
317 
318     private PowerManager.WakeLock mSuspendWakeLock;
319 
320     /**
321      * Interval in milliseconds between polling for RSSI
322      * and linkspeed information
323      */
324     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
325 
326     /**
327      * Interval in milliseconds between receiving a disconnect event
328      * while connected to a good AP, and handling the disconnect proper
329      */
330     private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000;
331 
332     /**
333      * Delay between supplicant restarts upon failure to establish connection
334      */
335     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
336 
337     /**
338      * Number of times we attempt to restart supplicant
339      */
340     private static final int SUPPLICANT_RESTART_TRIES = 5;
341 
342     private int mSupplicantRestartCount = 0;
343     /* Tracks sequence number on stop failure message */
344     private int mSupplicantStopFailureToken = 0;
345 
346     /**
347      * Tether state change notification time out
348      */
349     private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
350 
351     /* Tracks sequence number on a tether notification time out */
352     private int mTetherToken = 0;
353 
354     /**
355      * Driver start time out.
356      */
357     private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
358 
359     /* Tracks sequence number on a driver time out */
360     private int mDriverStartToken = 0;
361 
362     /**
363      * Don't select new network when previous network selection is
364      * pending connection for this much time
365      */
366     private static final int CONNECT_TIMEOUT_MSEC = 3000;
367 
368     /**
369      * The link properties of the wifi interface.
370      * Do not modify this directly; use updateLinkProperties instead.
371      */
372     private LinkProperties mLinkProperties;
373 
374     /* Tracks sequence number on a periodic scan message */
375     private int mPeriodicScanToken = 0;
376 
377     // Wakelock held during wifi start/stop and driver load/unload
378     private PowerManager.WakeLock mWakeLock;
379 
380     private Context mContext;
381 
382     private final Object mDhcpResultsLock = new Object();
383     private DhcpResults mDhcpResults;
384 
385     // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
386     private WifiInfo mWifiInfo;
387     private NetworkInfo mNetworkInfo;
388     private NetworkCapabilities mNetworkCapabilities;
389     private SupplicantStateTracker mSupplicantStateTracker;
390     private BaseDhcpStateMachine mDhcpStateMachine;
391     private boolean mDhcpActive = false;
392 
393     private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
394 
395     private final AtomicInteger mCountryCodeSequence = new AtomicInteger();
396 
397     // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress
398     private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
399 
400     // Roaming failure count
401     private int mRoamFailCount = 0;
402 
403     // This is the BSSID we are trying to associate to, it can be set to "any"
404     // if we havent selected a BSSID for joining.
405     // if we havent selected a BSSID for joining.
406     // The BSSID we are associated to is found in mWifiInfo
407     private String mTargetRoamBSSID = "any";
408 
409     private long mLastDriverRoamAttempt = 0;
410 
411     private WifiConfiguration targetWificonfiguration = null;
412 
413     // Used as debug to indicate which configuration last was saved
414     private WifiConfiguration lastSavedConfigurationAttempt = null;
415 
416     // Used as debug to indicate which configuration last was removed
417     private WifiConfiguration lastForgetConfigurationAttempt = null;
418 
419     //Random used by softAP channel Selection
420     private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis());
421 
isRoaming()422     boolean isRoaming() {
423         return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING
424                 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING;
425     }
426 
autoRoamSetBSSID(int netId, String bssid)427     public void autoRoamSetBSSID(int netId, String bssid) {
428         autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid);
429     }
430 
autoRoamSetBSSID(WifiConfiguration config, String bssid)431     public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) {
432         boolean ret = true;
433         if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any";
434         if (bssid == null) bssid = "any";
435         if (config == null) return false; // Nothing to do
436 
437         if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) {
438             return false; // We didnt change anything
439         }
440         if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) {
441             // Changing to ANY
442             if (!mWifiConfigStore.roamOnAny) {
443                 ret = false; // Nothing to do
444             }
445         }
446         if (VDBG) {
447             logd("autoRoamSetBSSID " + bssid + " key=" + config.configKey());
448         }
449         config.autoJoinBSSID = bssid;
450         mTargetRoamBSSID = bssid;
451         mWifiConfigStore.saveWifiConfigBSSID(config);
452         return ret;
453     }
454 
455     /**
456      * Save the UID correctly depending on if this is a new or existing network.
457      * @return true if operation is authorized, false otherwise
458      */
recordUidIfAuthorized(WifiConfiguration config, int uid, boolean onlyAnnotate)459     boolean recordUidIfAuthorized(WifiConfiguration config, int uid, boolean onlyAnnotate) {
460         if (!mWifiConfigStore.isNetworkConfigured(config)) {
461             config.creatorUid = uid;
462             config.creatorName = mContext.getPackageManager().getNameForUid(uid);
463         } else if (!mWifiConfigStore.canModifyNetwork(uid, config, onlyAnnotate)) {
464             return false;
465         }
466 
467         config.lastUpdateUid = uid;
468         config.lastUpdateName = mContext.getPackageManager().getNameForUid(uid);
469 
470         return true;
471 
472     }
473 
474     /**
475      * Checks to see if user has specified if the apps configuration is connectable.
476      * If the user hasn't specified we query the user and return true.
477      *
478      * @param message The message to be deferred
479      * @param netId Network id of the configuration to check against
480      * @param allowOverride If true we won't defer to the user if the uid of the message holds the
481      *                      CONFIG_OVERRIDE_PERMISSION
482      * @return True if we are waiting for user feedback or netId is invalid. False otherwise.
483      */
deferForUserInput(Message message, int netId, boolean allowOverride)484     boolean deferForUserInput(Message message, int netId, boolean allowOverride){
485         final WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(netId);
486 
487         // We can only evaluate saved configurations.
488         if (config == null) {
489             logd("deferForUserInput: configuration for netId=" + netId + " not stored");
490             return true;
491         }
492 
493         switch (config.userApproved) {
494             case WifiConfiguration.USER_APPROVED:
495             case WifiConfiguration.USER_BANNED:
496                 return false;
497             case WifiConfiguration.USER_PENDING:
498             default: // USER_UNSPECIFIED
499                /* the intention was to ask user here; but a dialog box is   *
500                 * too invasive; so we are going to allow connection for now */
501                 config.userApproved = WifiConfiguration.USER_APPROVED;
502                 return false;
503         }
504     }
505 
506     /**
507      * Subset of link properties coming from netlink.
508      * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
509      * and domains obtained from router advertisements (RFC 6106).
510      */
511     private NetlinkTracker mNetlinkTracker;
512 
513     private IpReachabilityMonitor mIpReachabilityMonitor;
514 
515     private AlarmManager mAlarmManager;
516     private PendingIntent mScanIntent;
517     private PendingIntent mDriverStopIntent;
518     private PendingIntent mPnoIntent;
519 
520     private int mDisconnectedPnoAlarmCount = 0;
521     /* Tracks current frequency mode */
522     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
523 
524     /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
525     private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
526 
527     // Channel for sending replies.
528     private AsyncChannel mReplyChannel = new AsyncChannel();
529 
530     private WifiP2pServiceImpl mWifiP2pServiceImpl;
531 
532     // Used to initiate a connection with WifiP2pService
533     private AsyncChannel mWifiP2pChannel;
534     private AsyncChannel mWifiApConfigChannel;
535 
536     private WifiScanner mWifiScanner;
537 
538     private int mConnectionRequests = 0;
539     private WifiNetworkFactory mNetworkFactory;
540     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
541     private WifiNetworkAgent mNetworkAgent;
542 
543     private String[] mWhiteListedSsids = null;
544 
545     // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
546     // We should really persist that into the networkHistory.txt file, and read it back when
547     // WifiStateMachine starts up
548     private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics();
549 
550     // Used to filter out requests we couldn't possibly satisfy.
551     private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
552 
553     /* The base for wifi message types */
554     static final int BASE = Protocol.BASE_WIFI;
555     /* Start the supplicant */
556     static final int CMD_START_SUPPLICANT                               = BASE + 11;
557     /* Stop the supplicant */
558     static final int CMD_STOP_SUPPLICANT                                = BASE + 12;
559     /* Start the driver */
560     static final int CMD_START_DRIVER                                   = BASE + 13;
561     /* Stop the driver */
562     static final int CMD_STOP_DRIVER                                    = BASE + 14;
563     /* Indicates Static IP succeeded */
564     static final int CMD_STATIC_IP_SUCCESS                              = BASE + 15;
565     /* Indicates Static IP failed */
566     static final int CMD_STATIC_IP_FAILURE                              = BASE + 16;
567     /* Indicates supplicant stop failed */
568     static final int CMD_STOP_SUPPLICANT_FAILED                         = BASE + 17;
569     /* Delayed stop to avoid shutting down driver too quick*/
570     static final int CMD_DELAYED_STOP_DRIVER                            = BASE + 18;
571     /* A delayed message sent to start driver when it fail to come up */
572     static final int CMD_DRIVER_START_TIMED_OUT                         = BASE + 19;
573 
574     /* Start the soft access point */
575     static final int CMD_START_AP                                       = BASE + 21;
576     /* Indicates soft ap start succeeded */
577     static final int CMD_START_AP_SUCCESS                               = BASE + 22;
578     /* Indicates soft ap start failed */
579     static final int CMD_START_AP_FAILURE                               = BASE + 23;
580     /* Stop the soft access point */
581     static final int CMD_STOP_AP                                        = BASE + 24;
582     /* Set the soft access point configuration */
583     static final int CMD_SET_AP_CONFIG                                  = BASE + 25;
584     /* Soft access point configuration set completed */
585     static final int CMD_SET_AP_CONFIG_COMPLETED                        = BASE + 26;
586     /* Request the soft access point configuration */
587     static final int CMD_REQUEST_AP_CONFIG                              = BASE + 27;
588     /* Response to access point configuration request */
589     static final int CMD_RESPONSE_AP_CONFIG                             = BASE + 28;
590     /* Invoked when getting a tether state change notification */
591     static final int CMD_TETHER_STATE_CHANGE                            = BASE + 29;
592     /* A delayed message sent to indicate tether state change failed to arrive */
593     static final int CMD_TETHER_NOTIFICATION_TIMED_OUT                  = BASE + 30;
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     /* Set the country code */
651     static final int CMD_SET_COUNTRY_CODE                               = BASE + 80;
652     /* Enables RSSI poll */
653     static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
654     /* RSSI poll */
655     static final int CMD_RSSI_POLL                                      = BASE + 83;
656     /* Set up packet filtering */
657     static final int CMD_START_PACKET_FILTERING                         = BASE + 84;
658     /* Clear packet filter */
659     static final int CMD_STOP_PACKET_FILTERING                          = BASE + 85;
660     /* Enable suspend mode optimizations in the driver */
661     static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
662     /* Delayed NETWORK_DISCONNECT */
663     static final int CMD_DELAYED_NETWORK_DISCONNECT                     = BASE + 87;
664     /* When there are no saved networks, we do a periodic scan to notify user of
665      * an open network */
666     static final int CMD_NO_NETWORKS_PERIODIC_SCAN                      = BASE + 88;
667     /* Test network Disconnection NETWORK_DISCONNECT */
668     static final int CMD_TEST_NETWORK_DISCONNECT                        = BASE + 89;
669 
670     private int testNetworkDisconnectCounter = 0;
671 
672     /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
673     static final int MULTICAST_V6 = 1;
674     static final int MULTICAST_V4 = 0;
675 
676     /* Set the frequency band */
677     static final int CMD_SET_FREQUENCY_BAND                             = BASE + 90;
678     /* Enable TDLS on a specific MAC address */
679     static final int CMD_ENABLE_TDLS                                    = BASE + 92;
680     /* DHCP/IP configuration watchdog */
681     static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER            = BASE + 93;
682 
683     /**
684      * Watchdog for protecting against b/16823537
685      * Leave time for 4-way handshake to succeed
686      */
687     static final int ROAM_GUARD_TIMER_MSEC = 15000;
688 
689     int roamWatchdogCount = 0;
690     /* Roam state watchdog */
691     static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
692     /* Screen change intent handling */
693     static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
694 
695     /* Disconnecting state watchdog */
696     static final int CMD_DISCONNECTING_WATCHDOG_TIMER                   = BASE + 96;
697 
698     /* Remove a packages associated configrations */
699     static final int CMD_REMOVE_APP_CONFIGURATIONS                      = BASE + 97;
700 
701     /* Disable an ephemeral network */
702     static final int CMD_DISABLE_EPHEMERAL_NETWORK                      = BASE + 98;
703 
704     /* Get matching network */
705     static final int CMD_GET_MATCHING_CONFIG                            = BASE + 99;
706 
707     /* alert from firmware */
708     static final int CMD_FIRMWARE_ALERT                                 = BASE + 100;
709 
710     /**
711      * Make this timer 40 seconds, which is about the normal DHCP timeout.
712      * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress
713      * for more than 30 seconds.
714      */
715     static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000;
716 
717     int obtainingIpWatchdogCount = 0;
718 
719     /* Commands from/to the SupplicantStateTracker */
720     /* Reset the supplicant state tracker */
721     static final int CMD_RESET_SUPPLICANT_STATE                         = BASE + 111;
722 
723     int disconnectingWatchdogCount = 0;
724     static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
725 
726     /* P2p commands */
727     /* We are ok with no response here since we wont do much with it anyway */
728     public static final int CMD_ENABLE_P2P                              = BASE + 131;
729     /* In order to shut down supplicant cleanly, we wait till p2p has
730      * been disabled */
731     public static final int CMD_DISABLE_P2P_REQ                         = BASE + 132;
732     public static final int CMD_DISABLE_P2P_RSP                         = BASE + 133;
733 
734     public static final int CMD_BOOT_COMPLETED                          = BASE + 134;
735 
736     /* We now have a valid IP configuration. */
737     static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
738     /* We no longer have a valid IP configuration. */
739     static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
740     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
741     static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
742 
743     /* Supplicant is trying to associate to a given BSSID */
744     static final int CMD_TARGET_BSSID                                   = BASE + 141;
745 
746     /* Reload all networks and reconnect */
747     static final int CMD_RELOAD_TLS_AND_RECONNECT                       = BASE + 142;
748 
749     static final int CMD_AUTO_CONNECT                                   = BASE + 143;
750 
751     private static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
752     private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
753     private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
754 
755     static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
756 
757     static final int CMD_AUTO_ROAM                                      = BASE + 145;
758 
759     static final int CMD_AUTO_SAVE_NETWORK                              = BASE + 146;
760 
761     static final int CMD_ASSOCIATED_BSSID                               = BASE + 147;
762 
763     static final int CMD_NETWORK_STATUS                                 = BASE + 148;
764 
765     /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
766     static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
767 
768     /* Remove a packages associated configrations */
769     static final int CMD_REMOVE_USER_CONFIGURATIONS                     = BASE + 152;
770 
771     static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
772 
773     /* used to restart PNO when it was stopped due to association attempt */
774     static final int CMD_RESTART_AUTOJOIN_OFFLOAD                       = BASE + 154;
775 
776     static int mRestartAutoJoinOffloadCounter = 0;
777 
778     /* used to log if PNO was started */
779     static final int CMD_STARTED_PNO_DBG                                = BASE + 155;
780 
781     static final int CMD_PNO_NETWORK_FOUND                              = BASE + 156;
782 
783     /* used to log if PNO was started */
784     static final int CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION              = BASE + 158;
785 
786     /* used to log if GSCAN was started */
787     static final int CMD_STARTED_GSCAN_DBG                              = BASE + 159;
788 
789 
790     /* Wifi state machine modes of operation */
791     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
792     public static final int CONNECT_MODE = 1;
793     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
794     public static final int SCAN_ONLY_MODE = 2;
795     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
796     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
797 
798     private static final int SUCCESS = 1;
799     private static final int FAILURE = -1;
800 
801     /* Tracks if suspend optimizations need to be disabled by DHCP,
802      * screen or due to high perf mode.
803      * When any of them needs to disable it, we keep the suspend optimizations
804      * disabled
805      */
806     private int mSuspendOptNeedsDisabled = 0;
807 
808     private static final int SUSPEND_DUE_TO_DHCP = 1;
809     private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
810     private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
811 
812     /* Tracks if user has enabled suspend optimizations through settings */
813     private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
814 
815     /**
816      * Default framework scan interval in milliseconds. This is used in the scenario in which
817      * wifi chipset does not support background scanning to set up a
818      * periodic wake up scan so that the device can connect to a new access
819      * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
820      * override this.
821      */
822     private final int mDefaultFrameworkScanIntervalMs;
823 
824 
825     /**
826      * Scan period for the NO_NETWORKS_PERIIDOC_SCAN_FEATURE
827      */
828     private final int mNoNetworksPeriodicScan;
829 
830     /**
831      * Supplicant scan interval in milliseconds.
832      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
833      * from the default config if the setting is not set
834      */
835     private long mSupplicantScanIntervalMs;
836 
837     /**
838      * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit
839      */
840     private long lastFullBandConnectedTimeMilli;
841 
842     /**
843      * time interval to the next full band scan we will perform for
844      * autojoin while connected with screen lit
845      */
846     private long fullBandConnectedTimeIntervalMilli;
847 
848     /**
849      * max time interval to the next full band scan we will perform for
850      * autojoin while connected with screen lit
851      * Max time is 5 minutes
852      */
853     private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5;
854 
855     /**
856      * Minimum time interval between enabling all networks.
857      * A device can end up repeatedly connecting to a bad network on screen on/off toggle
858      * due to enabling every time. We add a threshold to avoid this.
859      */
860     private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
861     private long mLastEnableAllNetworksTime;
862 
863     int mRunningBeaconCount = 0;
864 
865     /**
866      * Starting and shutting down driver too quick causes problems leading to driver
867      * being in a bad state. Delay driver stop.
868      */
869     private final int mDriverStopDelayMs;
870     private int mDelayedStopCounter;
871     private boolean mInDelayedStop = false;
872 
873     // there is a delay between StateMachine change country code and Supplicant change country code
874     // here save the current WifiStateMachine set country code
875     private volatile String mSetCountryCode = null;
876 
877     // Supplicant doesn't like setting the same country code multiple times (it may drop
878     // currently connected network), so we save the current device set country code here to avoid
879     // redundency
880     private String mDriverSetCountryCode = null;
881 
882     /* Default parent state */
883     private State mDefaultState = new DefaultState();
884     /* Temporary initial state */
885     private State mInitialState = new InitialState();
886     /* Driver loaded, waiting for supplicant to start */
887     private State mSupplicantStartingState = new SupplicantStartingState();
888     /* Driver loaded and supplicant ready */
889     private State mSupplicantStartedState = new SupplicantStartedState();
890     /* Waiting for supplicant to stop and monitor to exit */
891     private State mSupplicantStoppingState = new SupplicantStoppingState();
892     /* Driver start issued, waiting for completed event */
893     private State mDriverStartingState = new DriverStartingState();
894     /* Driver started */
895     private State mDriverStartedState = new DriverStartedState();
896     /* Wait until p2p is disabled
897      * This is a special state which is entered right after we exit out of DriverStartedState
898      * before transitioning to another state.
899      */
900     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
901     /* Driver stopping */
902     private State mDriverStoppingState = new DriverStoppingState();
903     /* Driver stopped */
904     private State mDriverStoppedState = new DriverStoppedState();
905     /* Scan for networks, no connection will be established */
906     private State mScanModeState = new ScanModeState();
907     /* Connecting to an access point */
908     private State mConnectModeState = new ConnectModeState();
909     /* Connected at 802.11 (L2) level */
910     private State mL2ConnectedState = new L2ConnectedState();
911     /* fetching IP after connection to access point (assoc+auth complete) */
912     private State mObtainingIpState = new ObtainingIpState();
913     /* Waiting for link quality verification to be complete */
914     private State mVerifyingLinkState = new VerifyingLinkState();
915     /* Connected with IP addr */
916     private State mConnectedState = new ConnectedState();
917     /* Roaming */
918     private State mRoamingState = new RoamingState();
919     /* disconnect issued, waiting for network disconnect confirmation */
920     private State mDisconnectingState = new DisconnectingState();
921     /* Network is not connected, supplicant assoc+auth is not complete */
922     private State mDisconnectedState = new DisconnectedState();
923     /* Waiting for WPS to be completed*/
924     private State mWpsRunningState = new WpsRunningState();
925 
926     /* Soft ap is starting up */
927     private State mSoftApStartingState = new SoftApStartingState();
928     /* Soft ap is running */
929     private State mSoftApStartedState = new SoftApStartedState();
930     /* Soft ap is running and we are waiting for tether notification */
931     private State mTetheringState = new TetheringState();
932     /* Soft ap is running and we are tethered through connectivity service */
933     private State mTetheredState = new TetheredState();
934     /* Waiting for untether confirmation before stopping soft Ap */
935     private State mUntetheringState = new UntetheringState();
936 
937 
938 
939     private class WifiScanListener implements WifiScanner.ScanListener {
940         @Override
onSuccess()941         public void onSuccess() {
942             Log.e(TAG, "WifiScanListener onSuccess");
943         };
944         @Override
onFailure(int reason, String description)945         public void onFailure(int reason, String description) {
946             Log.e(TAG, "WifiScanListener onFailure");
947         };
948         @Override
onPeriodChanged(int periodInMs)949         public void onPeriodChanged(int periodInMs) {
950             Log.e(TAG, "WifiScanListener onPeriodChanged  period=" + periodInMs);
951         }
952         @Override
onResults(WifiScanner.ScanData[] results)953         public void onResults(WifiScanner.ScanData[] results) {
954             Log.e(TAG, "WifiScanListener onResults2 "  + results.length);
955         }
956         @Override
onFullResult(ScanResult fullScanResult)957         public void onFullResult(ScanResult fullScanResult) {
958             Log.e(TAG, "WifiScanListener onFullResult " + fullScanResult.toString());
959         }
960 
WifiScanListener()961         WifiScanListener() {}
962     }
963 
964     WifiScanListener mWifiScanListener = new WifiScanListener();
965 
966 
967     private class TetherStateChange {
968         ArrayList<String> available;
969         ArrayList<String> active;
970 
TetherStateChange(ArrayList<String> av, ArrayList<String> ac)971         TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
972             available = av;
973             active = ac;
974         }
975     }
976 
977     public static class SimAuthRequestData {
978         int networkId;
979         int protocol;
980         String ssid;
981         // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
982         // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
983         String[] data;
984     }
985 
986     /**
987      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
988      * {@link WifiManager#WIFI_STATE_DISABLING},
989      * {@link WifiManager#WIFI_STATE_ENABLED},
990      * {@link WifiManager#WIFI_STATE_ENABLING},
991      * {@link WifiManager#WIFI_STATE_UNKNOWN}
992      */
993     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
994 
995     /**
996      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
997      * {@link WifiManager#WIFI_AP_STATE_DISABLING},
998      * {@link WifiManager#WIFI_AP_STATE_ENABLED},
999      * {@link WifiManager#WIFI_AP_STATE_ENABLING},
1000      * {@link WifiManager#WIFI_AP_STATE_FAILED}
1001      */
1002     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
1003 
1004     private static final int SCAN_REQUEST = 0;
1005     private static final String ACTION_START_SCAN =
1006             "com.android.server.WifiManager.action.START_SCAN";
1007 
1008     private static final int PNO_START_REQUEST = 0;
1009     private static final String ACTION_START_PNO =
1010             "com.android.server.WifiManager.action.START_PNO";
1011 
1012     private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
1013     private static final int DRIVER_STOP_REQUEST = 0;
1014     private static final String ACTION_DELAYED_DRIVER_STOP =
1015             "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
1016 
1017     /**
1018      * Keep track of whether WIFI is running.
1019      */
1020     private boolean mIsRunning = false;
1021 
1022     /**
1023      * Keep track of whether we last told the battery stats we had started.
1024      */
1025     private boolean mReportedRunning = false;
1026 
1027     /**
1028      * Most recently set source of starting WIFI.
1029      */
1030     private final WorkSource mRunningWifiUids = new WorkSource();
1031 
1032     /**
1033      * The last reported UIDs that were responsible for starting WIFI.
1034      */
1035     private final WorkSource mLastRunningWifiUids = new WorkSource();
1036 
1037     private final IBatteryStats mBatteryStats;
1038 
1039     private String mTcpBufferSizes = null;
1040 
1041     // Used for debug and stats gathering
1042     private static int sScanAlarmIntentCount = 0;
1043 
1044     final static int frameworkMinScanIntervalSaneValue = 10000;
1045 
1046     boolean mPnoEnabled;
1047     boolean mLazyRoamEnabled;
1048     long mGScanStartTimeMilli;
1049     long mGScanPeriodMilli;
1050 
WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller)1051     public WifiStateMachine(Context context, String wlanInterface,
1052                             WifiTrafficPoller trafficPoller) {
1053         super("WifiStateMachine");
1054         mContext = context;
1055         mSetCountryCode = Settings.Global.getString(
1056                 mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE);
1057         mInterfaceName = wlanInterface;
1058         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
1059         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
1060                 BatteryStats.SERVICE_NAME));
1061 
1062         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1063         mNwService = INetworkManagementService.Stub.asInterface(b);
1064 
1065         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
1066                 PackageManager.FEATURE_WIFI_DIRECT);
1067 
1068         mWifiNative = new WifiNative(mInterfaceName);
1069         mWifiConfigStore = new WifiConfigStore(context,this,  mWifiNative);
1070         mWifiAutoJoinController = new WifiAutoJoinController(context, this,
1071                 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);
1072         mWifiMonitor = new WifiMonitor(this, mWifiNative);
1073         mWifiLogger = new WifiLogger(this);
1074 
1075         mWifiInfo = new WifiInfo();
1076         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
1077                 getHandler());
1078         mLinkProperties = new LinkProperties();
1079 
1080         IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
1081         mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1);
1082 
1083         IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
1084 
1085         mNetworkInfo.setIsAvailable(false);
1086         mLastBssid = null;
1087         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1088         mLastSignalLevel = -1;
1089 
1090         mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() {
1091             public void update() {
1092                 sendMessage(CMD_UPDATE_LINKPROPERTIES);
1093             }
1094         });
1095         try {
1096             mNwService.registerObserver(mNetlinkTracker);
1097         } catch (RemoteException e) {
1098             loge("Couldn't register netlink tracker: " + e.toString());
1099         }
1100 
1101         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1102         mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST);
1103         mPnoIntent = getPrivateBroadcast(ACTION_START_PNO, PNO_START_REQUEST);
1104 
1105         // Make sure the interval is not configured less than 10 seconds
1106         int period = mContext.getResources().getInteger(
1107                 R.integer.config_wifi_framework_scan_interval);
1108         if (period < frameworkMinScanIntervalSaneValue) {
1109             period = frameworkMinScanIntervalSaneValue;
1110         }
1111         mDefaultFrameworkScanIntervalMs = period;
1112 
1113         mNoNetworksPeriodicScan = mContext.getResources().getInteger(
1114                 R.integer.config_wifi_no_network_periodic_scan_interval);
1115 
1116         mDriverStopDelayMs = mContext.getResources().getInteger(
1117                 R.integer.config_wifi_driver_stop_delay);
1118 
1119         mBackgroundScanSupported = mContext.getResources().getBoolean(
1120                 R.bool.config_wifi_background_scan_support);
1121 
1122         mPrimaryDeviceType = mContext.getResources().getString(
1123                 R.string.config_wifi_p2p_device_type);
1124 
1125         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
1126                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
1127 
1128         mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
1129         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
1130         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
1131         mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
1132         mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
1133         // TODO - needs to be a bit more dynamic
1134         mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
1135 
1136         mContext.registerReceiver(
1137                 new BroadcastReceiver() {
1138                     @Override
1139                     public void onReceive(Context context, Intent intent) {
1140                         ArrayList<String> available = intent.getStringArrayListExtra(
1141                                 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
1142                         ArrayList<String> active = intent.getStringArrayListExtra(
1143                                 ConnectivityManager.EXTRA_ACTIVE_TETHER);
1144                         sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
1145                     }
1146                 }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
1147 
1148         mContext.registerReceiver(
1149                 new BroadcastReceiver() {
1150                     @Override
1151                     public void onReceive(Context context, Intent intent) {
1152                         sScanAlarmIntentCount++; // Used for debug only
1153                         startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null);
1154                         if (VDBG)
1155                             logd("SCAN ALARM -> " + mDelayedScanCounter.get());
1156                     }
1157                 },
1158                 new IntentFilter(ACTION_START_SCAN));
1159 
1160         mContext.registerReceiver(
1161                 new BroadcastReceiver() {
1162                     @Override
1163                     public void onReceive(Context context, Intent intent) {
1164                         sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
1165                                 mRestartAutoJoinOffloadCounter, "pno alarm");
1166                         if (DBG)
1167                             logd("PNO START ALARM sent");
1168                     }
1169                 },
1170                 new IntentFilter(ACTION_START_PNO));
1171 
1172 
1173         IntentFilter filter = new IntentFilter();
1174         filter.addAction(Intent.ACTION_SCREEN_ON);
1175         filter.addAction(Intent.ACTION_SCREEN_OFF);
1176         mContext.registerReceiver(
1177                 new BroadcastReceiver() {
1178                     @Override
1179                     public void onReceive(Context context, Intent intent) {
1180                         String action = intent.getAction();
1181 
1182                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
1183                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
1184                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1185                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
1186                         }
1187                     }
1188                 }, filter);
1189 
1190         mContext.registerReceiver(
1191                 new BroadcastReceiver() {
1192                     @Override
1193                     public void onReceive(Context context, Intent intent) {
1194                         int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
1195                         sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
1196                     }
1197                 },
1198                 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
1199 
1200         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
1201                         Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
1202                 new ContentObserver(getHandler()) {
1203                     @Override
1204                     public void onChange(boolean selfChange) {
1205                         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
1206                                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
1207                     }
1208                 });
1209 
1210         mContext.registerReceiver(
1211                 new BroadcastReceiver() {
1212                     @Override
1213                     public void onReceive(Context context, Intent intent) {
1214                         sendMessage(CMD_BOOT_COMPLETED);
1215                     }
1216                 },
1217                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
1218 
1219         mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE);
1220 
1221         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1222         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
1223 
1224         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
1225         mSuspendWakeLock.setReferenceCounted(false);
1226 
1227         mTcpBufferSizes = mContext.getResources().getString(
1228                 com.android.internal.R.string.config_wifi_tcp_buffers);
1229 
1230         addState(mDefaultState);
1231             addState(mInitialState, mDefaultState);
1232             addState(mSupplicantStartingState, mDefaultState);
1233             addState(mSupplicantStartedState, mDefaultState);
1234                 addState(mDriverStartingState, mSupplicantStartedState);
1235                 addState(mDriverStartedState, mSupplicantStartedState);
1236                     addState(mScanModeState, mDriverStartedState);
1237                     addState(mConnectModeState, mDriverStartedState);
1238                         addState(mL2ConnectedState, mConnectModeState);
1239                             addState(mObtainingIpState, mL2ConnectedState);
1240                             addState(mVerifyingLinkState, mL2ConnectedState);
1241                             addState(mConnectedState, mL2ConnectedState);
1242                             addState(mRoamingState, mL2ConnectedState);
1243                         addState(mDisconnectingState, mConnectModeState);
1244                         addState(mDisconnectedState, mConnectModeState);
1245                         addState(mWpsRunningState, mConnectModeState);
1246                 addState(mWaitForP2pDisableState, mSupplicantStartedState);
1247                 addState(mDriverStoppingState, mSupplicantStartedState);
1248                 addState(mDriverStoppedState, mSupplicantStartedState);
1249             addState(mSupplicantStoppingState, mDefaultState);
1250             addState(mSoftApStartingState, mDefaultState);
1251             addState(mSoftApStartedState, mDefaultState);
1252                 addState(mTetheringState, mSoftApStartedState);
1253                 addState(mTetheredState, mSoftApStartedState);
1254                 addState(mUntetheringState, mSoftApStartedState);
1255 
1256         setInitialState(mInitialState);
1257 
1258         setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000);
1259         setLogOnlyTransitions(false);
1260         if (VDBG) setDbg(true);
1261 
1262         //start the state machine
1263         start();
1264 
1265         final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
1266         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1267         intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
1268         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1269     }
1270 
1271 
getPrivateBroadcast(String action, int requestCode)1272     PendingIntent getPrivateBroadcast(String action, int requestCode) {
1273         Intent intent = new Intent(action, null);
1274         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1275         //intent.setPackage(this.getClass().getPackage().getName());
1276         intent.setPackage("android");
1277         return PendingIntent.getBroadcast(mContext, requestCode, intent, 0);
1278     }
1279 
1280     private int mVerboseLoggingLevel = 0;
1281 
getVerboseLoggingLevel()1282     int getVerboseLoggingLevel() {
1283         return mVerboseLoggingLevel;
1284     }
1285 
enableVerboseLogging(int verbose)1286     void enableVerboseLogging(int verbose) {
1287         mVerboseLoggingLevel = verbose;
1288         if (verbose > 0) {
1289             DBG = true;
1290             VDBG = true;
1291             PDBG = true;
1292             mLogMessages = true;
1293             mWifiNative.setSupplicantLogLevel("DEBUG");
1294         } else {
1295             DBG = false;
1296             VDBG = false;
1297             PDBG = false;
1298             mLogMessages = false;
1299             mWifiNative.setSupplicantLogLevel("INFO");
1300         }
1301         mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
1302         mWifiAutoJoinController.enableVerboseLogging(verbose);
1303         mWifiMonitor.enableVerboseLogging(verbose);
1304         mWifiNative.enableVerboseLogging(verbose);
1305         mWifiConfigStore.enableVerboseLogging(verbose);
1306         mSupplicantStateTracker.enableVerboseLogging(verbose);
1307     }
1308 
setHalBasedAutojoinOffload(int enabled)1309     public void setHalBasedAutojoinOffload(int enabled) {
1310         // Shoult be used for debug only, triggered form developper settings
1311         // enabling HAl based PNO dynamically is not safe and not a normal operation
1312         mHalBasedPnoEnableInDevSettings = enabled > 0;
1313         mWifiConfigStore.enableHalBasedPno.set(mHalBasedPnoEnableInDevSettings);
1314         mWifiConfigStore.enableSsidWhitelist.set(mHalBasedPnoEnableInDevSettings);
1315         sendMessage(CMD_DISCONNECT);
1316     }
1317 
getHalBasedAutojoinOffload()1318     int getHalBasedAutojoinOffload() {
1319         return mHalBasedPnoEnableInDevSettings ? 1 : 0;
1320     }
1321 
useHalBasedAutoJoinOffload()1322     boolean useHalBasedAutoJoinOffload() {
1323         // all three settings need to be true:
1324         // - developper settings switch
1325         // - driver support
1326         // - config option
1327         return mHalBasedPnoEnableInDevSettings
1328                 && mHalBasedPnoDriverSupported
1329                 && mWifiConfigStore.enableHalBasedPno.get();
1330     }
1331 
allowFullBandScanAndAssociated()1332     boolean allowFullBandScanAndAssociated() {
1333 
1334         if (!getEnableAutoJoinWhenAssociated()) {
1335             if (DBG) {
1336                 Log.e(TAG, "allowFullBandScanAndAssociated: "
1337                         + " enableAutoJoinWhenAssociated : disallow");
1338             }
1339             return false;
1340         }
1341 
1342         if (mWifiInfo.txSuccessRate >
1343                 mWifiConfigStore.maxTxPacketForFullScans
1344                 || mWifiInfo.rxSuccessRate >
1345                 mWifiConfigStore.maxRxPacketForFullScans) {
1346             if (DBG) {
1347                 Log.e(TAG, "allowFullBandScanAndAssociated: packet rate tx"
1348                         + mWifiInfo.txSuccessRate + "  rx "
1349                         + mWifiInfo.rxSuccessRate
1350                         + " allow scan with traffic " + getAllowScansWithTraffic());
1351             }
1352             // Too much traffic at the interface, hence no full band scan
1353             if (getAllowScansWithTraffic() == 0) {
1354                 return false;
1355             }
1356         }
1357 
1358         if (getCurrentState() != mConnectedState) {
1359             if (DBG) {
1360                 Log.e(TAG, "allowFullBandScanAndAssociated: getCurrentState() : disallow");
1361             }
1362             return false;
1363         }
1364 
1365         return true;
1366     }
1367 
1368     long mLastScanPermissionUpdate = 0;
1369     boolean mConnectedModeGScanOffloadStarted = false;
1370     // Don't do a G-scan enable/re-enable cycle more than once within 20seconds
1371     // The function updateAssociatedScanPermission() can be called quite frequently, hence
1372     // we want to throttle the GScan Stop->Start transition
1373     static final long SCAN_PERMISSION_UPDATE_THROTTLE_MILLI = 20000;
updateAssociatedScanPermission()1374     void updateAssociatedScanPermission() {
1375 
1376         if (useHalBasedAutoJoinOffload()) {
1377             boolean allowed = allowFullBandScanAndAssociated();
1378 
1379             long now = System.currentTimeMillis();
1380             if (mConnectedModeGScanOffloadStarted && !allowed) {
1381                 if (DBG) {
1382                     Log.e(TAG, " useHalBasedAutoJoinOffload stop offload");
1383                 }
1384                 stopPnoOffload();
1385                 stopGScan(" useHalBasedAutoJoinOffload");
1386             }
1387             if (!mConnectedModeGScanOffloadStarted && allowed) {
1388                 if ((now - mLastScanPermissionUpdate) > SCAN_PERMISSION_UPDATE_THROTTLE_MILLI) {
1389                     // Re-enable Gscan offload, this will trigger periodic scans and allow firmware
1390                     // to look for 5GHz BSSIDs and better networks
1391                     if (DBG) {
1392                         Log.e(TAG, " useHalBasedAutoJoinOffload restart offload");
1393                     }
1394                     startGScanConnectedModeOffload("updatePermission "
1395                             + (now - mLastScanPermissionUpdate) + "ms");
1396                     mLastScanPermissionUpdate = now;
1397                 }
1398             }
1399         }
1400     }
1401 
1402     private int mAggressiveHandover = 0;
1403 
getAggressiveHandover()1404     int getAggressiveHandover() {
1405         return mAggressiveHandover;
1406     }
1407 
enableAggressiveHandover(int enabled)1408     void enableAggressiveHandover(int enabled) {
1409         mAggressiveHandover = enabled;
1410     }
1411 
clearANQPCache()1412     public void clearANQPCache() {
1413         mWifiConfigStore.trimANQPCache(true);
1414     }
1415 
setAllowScansWithTraffic(int enabled)1416     public void setAllowScansWithTraffic(int enabled) {
1417         mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled);
1418     }
1419 
getAllowScansWithTraffic()1420     public int getAllowScansWithTraffic() {
1421         return mWifiConfigStore.alwaysEnableScansWhileAssociated.get();
1422     }
1423 
enableAutoJoinWhenAssociated(boolean enabled)1424     public boolean enableAutoJoinWhenAssociated(boolean enabled) {
1425         boolean old_state = getEnableAutoJoinWhenAssociated();
1426         mWifiConfigStore.enableAutoJoinWhenAssociated.set(enabled);
1427         if (!old_state && enabled && mScreenOn && getCurrentState() == mConnectedState) {
1428             startDelayedScan(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(), null,
1429                     null);
1430         }
1431         return true;
1432     }
1433 
getEnableAutoJoinWhenAssociated()1434     public boolean getEnableAutoJoinWhenAssociated() {
1435         return mWifiConfigStore.enableAutoJoinWhenAssociated.get();
1436     }
1437     /*
1438      *
1439      * Framework scan control
1440      */
1441 
1442     private boolean mAlarmEnabled = false;
1443 
1444     private AtomicInteger mDelayedScanCounter = new AtomicInteger();
1445 
setScanAlarm(boolean enabled)1446     private void setScanAlarm(boolean enabled) {
1447         if (PDBG) {
1448             String state;
1449             if (enabled) state = "enabled"; else state = "disabled";
1450             logd("setScanAlarm " + state
1451                     + " defaultperiod " + mDefaultFrameworkScanIntervalMs
1452                     + " mBackgroundScanSupported " + mBackgroundScanSupported);
1453         }
1454         if (mBackgroundScanSupported == false) {
1455             // Scan alarm is only used for background scans if they are not
1456             // offloaded to the wifi chipset, hence enable the scan alarm
1457             // gicing us RTC_WAKEUP of backgroundScan is NOT supported
1458             enabled = true;
1459         }
1460 
1461         if (enabled == mAlarmEnabled) return;
1462         if (enabled) {
1463             /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */
1464             /* going to wake up the host processor to look for access points */
1465             mAlarmManager.set(AlarmManager.RTC_WAKEUP,
1466                     System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs,
1467                     mScanIntent);
1468             mAlarmEnabled = true;
1469         } else {
1470             mAlarmManager.cancel(mScanIntent);
1471             mAlarmEnabled = false;
1472         }
1473     }
1474 
cancelDelayedScan()1475     private void cancelDelayedScan() {
1476         mDelayedScanCounter.incrementAndGet();
1477     }
1478 
checkAndRestartDelayedScan(int counter, boolean restart, int milli, ScanSettings settings, WorkSource workSource)1479     private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli,
1480                                                ScanSettings settings, WorkSource workSource) {
1481 
1482         if (counter != mDelayedScanCounter.get()) {
1483             return false;
1484         }
1485         if (restart)
1486             startDelayedScan(milli, settings, workSource);
1487         return true;
1488     }
1489 
startDelayedScan(int milli, ScanSettings settings, WorkSource workSource)1490     private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) {
1491         if (milli <= 0) return;
1492         /**
1493          * The cases where the scan alarm should be run are :
1494          * - DisconnectedState && screenOn => used delayed timer
1495          * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO
1496          * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm
1497          * - ConnectedState && screenOn => used delayed timer
1498          */
1499 
1500         mDelayedScanCounter.incrementAndGet();
1501         if (mScreenOn &&
1502                 (getCurrentState() == mDisconnectedState
1503                         || getCurrentState() == mConnectedState)) {
1504             Bundle bundle = new Bundle();
1505             bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
1506             bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1507             bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
1508             sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE,
1509                     mDelayedScanCounter.get(), bundle, milli);
1510             if (DBG) logd("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli);
1511         } else if (mBackgroundScanSupported == false
1512                 && !mScreenOn && getCurrentState() == mDisconnectedState) {
1513             setScanAlarm(true);
1514             if (DBG) logd("startDelayedScan start scan alarm -> "
1515                     + mDelayedScanCounter + " milli " + milli);
1516         } else {
1517             if (DBG) logd("startDelayedScan unhandled -> "
1518                     + mDelayedScanCounter + " milli " + milli);
1519         }
1520     }
1521 
setRandomMacOui()1522     private boolean setRandomMacOui() {
1523         String oui = mContext.getResources().getString(
1524                 R.string.config_wifi_random_mac_oui, GOOGLE_OUI);
1525         String[] ouiParts = oui.split("-");
1526         byte[] ouiBytes = new byte[3];
1527         ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF);
1528         ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF);
1529         ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF);
1530 
1531         logd("Setting OUI to " + oui);
1532         return mWifiNative.setScanningMacOui(ouiBytes);
1533     }
1534 
1535     /**
1536      * ******************************************************
1537      * Methods exposed for public use
1538      * ******************************************************
1539      */
1540 
getMessenger()1541     public Messenger getMessenger() {
1542         return new Messenger(getHandler());
1543     }
1544 
getWifiMonitor()1545     public WifiMonitor getWifiMonitor() {
1546         return mWifiMonitor;
1547     }
1548 
1549     /**
1550      * TODO: doc
1551      */
syncPingSupplicant(AsyncChannel channel)1552     public boolean syncPingSupplicant(AsyncChannel channel) {
1553         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
1554         boolean result = (resultMsg.arg1 != FAILURE);
1555         resultMsg.recycle();
1556         return result;
1557     }
1558 
syncGetChannelList(AsyncChannel channel)1559     public List<WifiChannel> syncGetChannelList(AsyncChannel channel) {
1560         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ);
1561         List<WifiChannel> list = null;
1562         if (resultMsg.obj != null) {
1563             list = new ArrayList<WifiChannel>();
1564             String freqs = (String) resultMsg.obj;
1565             String[] lines = freqs.split("\n");
1566             for (String line : lines)
1567                 if (line.contains("MHz")) {
1568                     // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)"
1569                     WifiChannel c = new WifiChannel();
1570                     String[] prop = line.split(" ");
1571                     if (prop.length < 5) continue;
1572                     try {
1573                         c.channelNum = Integer.parseInt(prop[1]);
1574                         c.freqMHz = Integer.parseInt(prop[3]);
1575                     } catch (NumberFormatException e) {
1576                     }
1577                     c.isDFS = line.contains("(DFS)");
1578                     list.add(c);
1579                 } else if (line.contains("Mode[B] Channels:")) {
1580                     // B channels are the same as G channels, skipped
1581                     break;
1582                 }
1583         }
1584         resultMsg.recycle();
1585         return (list != null && list.size() > 0) ? list : null;
1586     }
1587 
1588     /**
1589      * When settings allowing making use of untrusted networks change, trigger a scan
1590      * so as to kick of autojoin.
1591      */
startScanForUntrustedSettingChange()1592     public void startScanForUntrustedSettingChange() {
1593         startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null);
1594     }
1595 
1596     /**
1597      * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
1598      * given to callingUid.
1599      *
1600      * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
1601      *                   workSource is specified.
1602      * @param workSource If not null, blame is given to workSource.
1603      * @param settings   Scan settings, see {@link ScanSettings}.
1604      */
startScan(int callingUid, int scanCounter, ScanSettings settings, WorkSource workSource)1605     public void startScan(int callingUid, int scanCounter,
1606                           ScanSettings settings, WorkSource workSource) {
1607         Bundle bundle = new Bundle();
1608         bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
1609         bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1610         bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
1611         sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
1612     }
1613 
1614     // called from BroadcastListener
1615 
1616     /**
1617      * Start reading new scan data
1618      * Data comes in as:
1619      * "scancount=5\n"
1620      * "nextcount=5\n"
1621      * "apcount=3\n"
1622      * "trunc\n" (optional)
1623      * "bssid=...\n"
1624      * "ssid=...\n"
1625      * "freq=...\n" (in Mhz)
1626      * "level=...\n"
1627      * "dist=...\n" (in cm)
1628      * "distsd=...\n" (standard deviation, in cm)
1629      * "===="
1630      * "bssid=...\n"
1631      * etc
1632      * "===="
1633      * "bssid=...\n"
1634      * etc
1635      * "%%%%"
1636      * "apcount=2\n"
1637      * "bssid=...\n"
1638      * etc
1639      * "%%%%
1640      * etc
1641      * "----"
1642      */
1643     private final static boolean DEBUG_PARSE = false;
1644 
1645     private long mDisconnectedTimeStamp = 0;
1646 
getDisconnectedTimeMilli()1647     public long getDisconnectedTimeMilli() {
1648         if (getCurrentState() == mDisconnectedState
1649                 && mDisconnectedTimeStamp != 0) {
1650             long now_ms = System.currentTimeMillis();
1651             return now_ms - mDisconnectedTimeStamp;
1652         }
1653         return 0;
1654     }
1655 
1656     // Keeping track of scan requests
1657     private long lastStartScanTimeStamp = 0;
1658     private long lastScanDuration = 0;
1659     // Last connect attempt is used to prevent scan requests:
1660     //  - for a period of 10 seconds after attempting to connect
1661     private long lastConnectAttemptTimestamp = 0;
1662     private String lastScanFreqs = null;
1663 
1664     // For debugging, keep track of last message status handling
1665     // TODO, find an equivalent mechanism as part of parent class
1666     private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
1667     private static int MESSAGE_HANDLING_STATUS_OK = 1;
1668     private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
1669     private static int MESSAGE_HANDLING_STATUS_REFUSED = -1;
1670     private static int MESSAGE_HANDLING_STATUS_FAIL = -2;
1671     private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
1672     private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
1673     private static int MESSAGE_HANDLING_STATUS_DISCARD = -5;
1674     private static int MESSAGE_HANDLING_STATUS_LOOPED = -6;
1675     private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
1676 
1677     private int messageHandlingStatus = 0;
1678 
1679     //TODO: this is used only to track connection attempts, however the link state and packet per
1680     //TODO: second logic should be folded into that
checkOrDeferScanAllowed(Message msg)1681     private boolean checkOrDeferScanAllowed(Message msg) {
1682         long now = System.currentTimeMillis();
1683         if (lastConnectAttemptTimestamp != 0 && (now - lastConnectAttemptTimestamp) < 10000) {
1684             Message dmsg = Message.obtain(msg);
1685             sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttemptTimestamp));
1686             return false;
1687         }
1688         return true;
1689     }
1690 
1691     private int mOnTime = 0;
1692     private int mTxTime = 0;
1693     private int mRxTime = 0;
1694     private int mOnTimeStartScan = 0;
1695     private int mTxTimeStartScan = 0;
1696     private int mRxTimeStartScan = 0;
1697     private int mOnTimeScan = 0;
1698     private int mTxTimeScan = 0;
1699     private int mRxTimeScan = 0;
1700     private int mOnTimeThisScan = 0;
1701     private int mTxTimeThisScan = 0;
1702     private int mRxTimeThisScan = 0;
1703 
1704     private int mOnTimeScreenStateChange = 0;
1705     private int mOnTimeAtLastReport = 0;
1706     private long lastOntimeReportTimeStamp = 0;
1707     private long lastScreenStateChangeTimeStamp = 0;
1708     private int mOnTimeLastReport = 0;
1709     private int mTxTimeLastReport = 0;
1710     private int mRxTimeLastReport = 0;
1711 
1712     private long lastLinkLayerStatsUpdate = 0;
1713 
reportOnTime()1714     String reportOnTime() {
1715         long now = System.currentTimeMillis();
1716         StringBuilder sb = new StringBuilder();
1717         // Report stats since last report
1718         int on = mOnTime - mOnTimeLastReport;
1719         mOnTimeLastReport = mOnTime;
1720         int tx = mTxTime - mTxTimeLastReport;
1721         mTxTimeLastReport = mTxTime;
1722         int rx = mRxTime - mRxTimeLastReport;
1723         mRxTimeLastReport = mRxTime;
1724         int period = (int) (now - lastOntimeReportTimeStamp);
1725         lastOntimeReportTimeStamp = now;
1726         sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
1727         // Report stats since Screen State Changed
1728         on = mOnTime - mOnTimeScreenStateChange;
1729         period = (int) (now - lastScreenStateChangeTimeStamp);
1730         sb.append(String.format(" from screen [on:%d period:%d]", on, period));
1731         return sb.toString();
1732     }
1733 
getWifiLinkLayerStats(boolean dbg)1734     WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) {
1735         WifiLinkLayerStats stats = null;
1736         if (mWifiLinkLayerStatsSupported > 0) {
1737             String name = "wlan0";
1738             stats = mWifiNative.getWifiLinkLayerStats(name);
1739             if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
1740                 mWifiLinkLayerStatsSupported -= 1;
1741             } else if (stats != null) {
1742                 lastLinkLayerStatsUpdate = System.currentTimeMillis();
1743                 mOnTime = stats.on_time;
1744                 mTxTime = stats.tx_time;
1745                 mRxTime = stats.rx_time;
1746                 mRunningBeaconCount = stats.beacon_rx;
1747             }
1748         }
1749         if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
1750             long mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1751             long mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1752             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
1753         } else {
1754             mWifiInfo.updatePacketRates(stats);
1755         }
1756         if (useHalBasedAutoJoinOffload()) {
1757             sendMessage(CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION);
1758         }
1759         return stats;
1760     }
1761 
startRadioScanStats()1762     void startRadioScanStats() {
1763         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
1764         if (stats != null) {
1765             mOnTimeStartScan = stats.on_time;
1766             mTxTimeStartScan = stats.tx_time;
1767             mRxTimeStartScan = stats.rx_time;
1768             mOnTime = stats.on_time;
1769             mTxTime = stats.tx_time;
1770             mRxTime = stats.rx_time;
1771         }
1772     }
1773 
closeRadioScanStats()1774     void closeRadioScanStats() {
1775         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
1776         if (stats != null) {
1777             mOnTimeThisScan = stats.on_time - mOnTimeStartScan;
1778             mTxTimeThisScan = stats.tx_time - mTxTimeStartScan;
1779             mRxTimeThisScan = stats.rx_time - mRxTimeStartScan;
1780             mOnTimeScan += mOnTimeThisScan;
1781             mTxTimeScan += mTxTimeThisScan;
1782             mRxTimeScan += mRxTimeThisScan;
1783         }
1784     }
1785 
1786     // If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
noteScanStart(int callingUid, WorkSource workSource)1787     private void noteScanStart(int callingUid, WorkSource workSource) {
1788         long now = System.currentTimeMillis();
1789         lastStartScanTimeStamp = now;
1790         lastScanDuration = 0;
1791         if (DBG) {
1792             String ts = String.format("[%,d ms]", now);
1793             if (workSource != null) {
1794                 if (DBG) logd(ts + " noteScanStart" + workSource.toString()
1795                         + " uid " + Integer.toString(callingUid));
1796             } else {
1797                 if (DBG) logd(ts + " noteScanstart no scan source"
1798                         + " uid " + Integer.toString(callingUid));
1799             }
1800         }
1801         startRadioScanStats();
1802         if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE
1803                 && callingUid != SCAN_ALARM_SOURCE)
1804                 || workSource != null)) {
1805             mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid);
1806 
1807             WorkSource batteryWorkSource = mScanWorkSource;
1808             if (mScanWorkSource.size() == 1 && mScanWorkSource.get(0) < 0) {
1809                 // WiFi uses negative UIDs to mean special things. BatteryStats don't care!
1810                 batteryWorkSource = new WorkSource(Process.WIFI_UID);
1811             }
1812 
1813             try {
1814                 mBatteryStats.noteWifiScanStartedFromSource(batteryWorkSource);
1815             } catch (RemoteException e) {
1816                 log(e.toString());
1817             }
1818         }
1819     }
1820 
noteScanEnd()1821     private void noteScanEnd() {
1822         long now = System.currentTimeMillis();
1823         if (lastStartScanTimeStamp != 0) {
1824             lastScanDuration = now - lastStartScanTimeStamp;
1825         }
1826         lastStartScanTimeStamp = 0;
1827         if (DBG) {
1828             String ts = String.format("[%,d ms]", now);
1829             if (mScanWorkSource != null)
1830                 logd(ts + " noteScanEnd " + mScanWorkSource.toString()
1831                         + " onTime=" + mOnTimeThisScan);
1832             else
1833                 logd(ts + " noteScanEnd no scan source"
1834                         + " onTime=" + mOnTimeThisScan);
1835         }
1836         if (mScanWorkSource != null) {
1837             try {
1838                 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
1839             } catch (RemoteException e) {
1840                 log(e.toString());
1841             } finally {
1842                 mScanWorkSource = null;
1843             }
1844         }
1845     }
1846 
handleScanRequest(int type, Message message)1847     private void handleScanRequest(int type, Message message) {
1848         ScanSettings settings = null;
1849         WorkSource workSource = null;
1850 
1851         // unbundle parameters
1852         Bundle bundle = (Bundle) message.obj;
1853 
1854         if (bundle != null) {
1855             settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
1856             workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
1857         }
1858 
1859         // parse scan settings
1860         String freqs = null;
1861         if (settings != null && settings.channelSet != null) {
1862             StringBuilder sb = new StringBuilder();
1863             boolean first = true;
1864             for (WifiChannel channel : settings.channelSet) {
1865                 if (!first) sb.append(',');
1866                 else first = false;
1867                 sb.append(channel.freqMHz);
1868             }
1869             freqs = sb.toString();
1870         }
1871 
1872         // call wifi native to start the scan
1873         if (startScanNative(type, freqs)) {
1874             // only count battery consumption if scan request is accepted
1875             noteScanStart(message.arg1, workSource);
1876             // a full scan covers everything, clearing scan request buffer
1877             if (freqs == null)
1878                 mBufferedScanMsg.clear();
1879             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
1880             if (workSource != null) {
1881                 // External worksource was passed along the scan request,
1882                 // hence always send a broadcast
1883                 mSendScanResultsBroadcast = true;
1884             }
1885             return;
1886         }
1887 
1888         // if reach here, scan request is rejected
1889 
1890         if (!mIsScanOngoing) {
1891             // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
1892 
1893             // discard this request and pop up the next one
1894             if (mBufferedScanMsg.size() > 0) {
1895                 sendMessage(mBufferedScanMsg.remove());
1896             }
1897             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
1898         } else if (!mIsFullScanOngoing) {
1899             // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
1900             // buffer the scan request to make sure specified channels will be scanned eventually
1901             if (freqs == null)
1902                 mBufferedScanMsg.clear();
1903             if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
1904                 Message msg = obtainMessage(CMD_START_SCAN,
1905                         message.arg1, message.arg2, bundle);
1906                 mBufferedScanMsg.add(msg);
1907             } else {
1908                 // if too many requests in buffer, combine them into a single full scan
1909                 bundle = new Bundle();
1910                 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
1911                 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
1912                 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
1913                 mBufferedScanMsg.clear();
1914                 mBufferedScanMsg.add(msg);
1915             }
1916             messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
1917         } else {
1918             // mIsScanOngoing and mIsFullScanOngoing
1919             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
1920         }
1921     }
1922 
1923 
1924     /**
1925      * return true iff scan request is accepted
1926      */
startScanNative(int type, String freqs)1927     private boolean startScanNative(int type, String freqs) {
1928         if (mWifiNative.scan(type, freqs)) {
1929             mIsScanOngoing = true;
1930             mIsFullScanOngoing = (freqs == null);
1931             lastScanFreqs = freqs;
1932             return true;
1933         }
1934         return false;
1935     }
1936 
1937     /**
1938      * TODO: doc
1939      */
setSupplicantRunning(boolean enable)1940     public void setSupplicantRunning(boolean enable) {
1941         if (enable) {
1942             sendMessage(CMD_START_SUPPLICANT);
1943         } else {
1944             sendMessage(CMD_STOP_SUPPLICANT);
1945         }
1946     }
1947 
1948     /**
1949      * TODO: doc
1950      */
setHostApRunning(WifiConfiguration wifiConfig, boolean enable)1951     public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
1952         if (enable) {
1953             sendMessage(CMD_START_AP, wifiConfig);
1954         } else {
1955             sendMessage(CMD_STOP_AP);
1956         }
1957     }
1958 
setWifiApConfiguration(WifiConfiguration config)1959     public void setWifiApConfiguration(WifiConfiguration config) {
1960         mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
1961     }
1962 
syncGetWifiApConfiguration()1963     public WifiConfiguration syncGetWifiApConfiguration() {
1964         Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
1965         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
1966         resultMsg.recycle();
1967         return ret;
1968     }
1969 
1970     /**
1971      * TODO: doc
1972      */
syncGetWifiState()1973     public int syncGetWifiState() {
1974         return mWifiState.get();
1975     }
1976 
1977     /**
1978      * TODO: doc
1979      */
syncGetWifiStateByName()1980     public String syncGetWifiStateByName() {
1981         switch (mWifiState.get()) {
1982             case WIFI_STATE_DISABLING:
1983                 return "disabling";
1984             case WIFI_STATE_DISABLED:
1985                 return "disabled";
1986             case WIFI_STATE_ENABLING:
1987                 return "enabling";
1988             case WIFI_STATE_ENABLED:
1989                 return "enabled";
1990             case WIFI_STATE_UNKNOWN:
1991                 return "unknown state";
1992             default:
1993                 return "[invalid state]";
1994         }
1995     }
1996 
1997     /**
1998      * TODO: doc
1999      */
syncGetWifiApState()2000     public int syncGetWifiApState() {
2001         return mWifiApState.get();
2002     }
2003 
2004     /**
2005      * TODO: doc
2006      */
syncGetWifiApStateByName()2007     public String syncGetWifiApStateByName() {
2008         switch (mWifiApState.get()) {
2009             case WIFI_AP_STATE_DISABLING:
2010                 return "disabling";
2011             case WIFI_AP_STATE_DISABLED:
2012                 return "disabled";
2013             case WIFI_AP_STATE_ENABLING:
2014                 return "enabling";
2015             case WIFI_AP_STATE_ENABLED:
2016                 return "enabled";
2017             case WIFI_AP_STATE_FAILED:
2018                 return "failed";
2019             default:
2020                 return "[invalid state]";
2021         }
2022     }
2023 
2024     /**
2025      * Get status information for the current connection, if any.
2026      *
2027      * @return a {@link WifiInfo} object containing information about the current connection
2028      */
syncRequestConnectionInfo()2029     public WifiInfo syncRequestConnectionInfo() {
2030         return getWiFiInfoForUid(Binder.getCallingUid());
2031     }
2032 
syncGetDhcpResults()2033     public DhcpResults syncGetDhcpResults() {
2034         synchronized (mDhcpResultsLock) {
2035             return new DhcpResults(mDhcpResults);
2036         }
2037     }
2038 
2039     /**
2040      * TODO: doc
2041      */
setDriverStart(boolean enable)2042     public void setDriverStart(boolean enable) {
2043         if (enable) {
2044             sendMessage(CMD_START_DRIVER);
2045         } else {
2046             sendMessage(CMD_STOP_DRIVER);
2047         }
2048     }
2049 
2050     /**
2051      * TODO: doc
2052      */
setOperationalMode(int mode)2053     public void setOperationalMode(int mode) {
2054         if (DBG) log("setting operational mode to " + String.valueOf(mode));
2055         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
2056     }
2057 
2058     /**
2059      * TODO: doc
2060      */
syncGetScanResultsList()2061     public List<ScanResult> syncGetScanResultsList() {
2062         synchronized (mScanResultCache) {
2063             List<ScanResult> scanList = new ArrayList<ScanResult>();
2064             for (ScanDetail result : mScanResults) {
2065                 scanList.add(new ScanResult(result.getScanResult()));
2066             }
2067             return scanList;
2068         }
2069     }
2070 
disableEphemeralNetwork(String SSID)2071     public void disableEphemeralNetwork(String SSID) {
2072         if (SSID != null) {
2073             sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID);
2074         }
2075     }
2076 
2077     /**
2078      * Get unsynchronized pointer to scan result list
2079      * Can be called only from AutoJoinController which runs in the WifiStateMachine context
2080      */
getScanResultsListNoCopyUnsync()2081     public List<ScanDetail> getScanResultsListNoCopyUnsync() {
2082         return mScanResults;
2083     }
2084 
2085     /**
2086      * Disconnect from Access Point
2087      */
disconnectCommand()2088     public void disconnectCommand() {
2089         sendMessage(CMD_DISCONNECT);
2090     }
2091 
disconnectCommand(int uid, int reason)2092     public void disconnectCommand(int uid, int reason) {
2093         sendMessage(CMD_DISCONNECT, uid, reason);
2094     }
2095 
2096     /**
2097      * Initiate a reconnection to AP
2098      */
reconnectCommand()2099     public void reconnectCommand() {
2100         sendMessage(CMD_RECONNECT);
2101     }
2102 
2103     /**
2104      * Initiate a re-association to AP
2105      */
reassociateCommand()2106     public void reassociateCommand() {
2107         sendMessage(CMD_REASSOCIATE);
2108     }
2109 
2110     /**
2111      * Reload networks and then reconnect; helps load correct data for TLS networks
2112      */
2113 
reloadTlsNetworksAndReconnect()2114     public void reloadTlsNetworksAndReconnect() {
2115         sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
2116     }
2117 
2118     /**
2119      * Add a network synchronously
2120      *
2121      * @return network id of the new network
2122      */
syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config)2123     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
2124         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
2125         int result = resultMsg.arg1;
2126         resultMsg.recycle();
2127         return result;
2128     }
2129 
2130     /**
2131      * Get configured networks synchronously
2132      *
2133      * @param channel
2134      * @return
2135      */
2136 
syncGetConfiguredNetworks(int uuid, AsyncChannel channel)2137     public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
2138         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
2139         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
2140         resultMsg.recycle();
2141         return result;
2142     }
2143 
syncGetPrivilegedConfiguredNetwork(AsyncChannel channel)2144     public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
2145         Message resultMsg = channel.sendMessageSynchronously(
2146                 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS);
2147         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
2148         resultMsg.recycle();
2149         return result;
2150     }
2151 
syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel)2152     public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) {
2153         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult);
2154         return (WifiConfiguration) resultMsg.obj;
2155     }
2156 
2157     /**
2158      * Get connection statistics synchronously
2159      *
2160      * @param channel
2161      * @return
2162      */
2163 
syncGetConnectionStatistics(AsyncChannel channel)2164     public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) {
2165         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS);
2166         WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj;
2167         resultMsg.recycle();
2168         return result;
2169     }
2170 
2171     /**
2172      * Get adaptors synchronously
2173      */
2174 
syncGetSupportedFeatures(AsyncChannel channel)2175     public int syncGetSupportedFeatures(AsyncChannel channel) {
2176         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
2177         int supportedFeatureSet = resultMsg.arg1;
2178         resultMsg.recycle();
2179         return supportedFeatureSet;
2180     }
2181 
2182     /**
2183      * Get link layers stats for adapter synchronously
2184      */
syncGetLinkLayerStats(AsyncChannel channel)2185     public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
2186         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
2187         WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
2188         resultMsg.recycle();
2189         return result;
2190     }
2191 
2192     /**
2193      * Delete a network
2194      *
2195      * @param networkId id of the network to be removed
2196      */
syncRemoveNetwork(AsyncChannel channel, int networkId)2197     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
2198         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
2199         boolean result = (resultMsg.arg1 != FAILURE);
2200         resultMsg.recycle();
2201         return result;
2202     }
2203 
2204     /**
2205      * Enable a network
2206      *
2207      * @param netId         network id of the network
2208      * @param disableOthers true, if all other networks have to be disabled
2209      * @return {@code true} if the operation succeeds, {@code false} otherwise
2210      */
syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers)2211     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
2212         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
2213                 disableOthers ? 1 : 0);
2214         boolean result = (resultMsg.arg1 != FAILURE);
2215         resultMsg.recycle();
2216         return result;
2217     }
2218 
2219     /**
2220      * Disable a network
2221      *
2222      * @param netId network id of the network
2223      * @return {@code true} if the operation succeeds, {@code false} otherwise
2224      */
syncDisableNetwork(AsyncChannel channel, int netId)2225     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
2226         Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
2227         boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
2228         resultMsg.recycle();
2229         return result;
2230     }
2231 
2232     /**
2233      * Retrieves a WPS-NFC configuration token for the specified network
2234      *
2235      * @return a hex string representation of the WPS-NFC configuration token
2236      */
syncGetWpsNfcConfigurationToken(int netId)2237     public String syncGetWpsNfcConfigurationToken(int netId) {
2238         return mWifiNative.getNfcWpsConfigurationToken(netId);
2239     }
2240 
enableBackgroundScan(boolean enable)2241     void enableBackgroundScan(boolean enable) {
2242         if (enable) {
2243             mWifiConfigStore.enableAllNetworks();
2244         }
2245         boolean ret = mWifiNative.enableBackgroundScan(enable);
2246         if (ret) {
2247             mLegacyPnoEnabled = enable;
2248         } else {
2249             Log.e(TAG, " Fail to set up pno, want " + enable + " now " + mLegacyPnoEnabled);
2250         }
2251     }
2252 
2253     /**
2254      * Blacklist a BSSID. This will avoid the AP if there are
2255      * alternate APs to connect
2256      *
2257      * @param bssid BSSID of the network
2258      */
addToBlacklist(String bssid)2259     public void addToBlacklist(String bssid) {
2260         sendMessage(CMD_BLACKLIST_NETWORK, bssid);
2261     }
2262 
2263     /**
2264      * Clear the blacklist list
2265      */
clearBlacklist()2266     public void clearBlacklist() {
2267         sendMessage(CMD_CLEAR_BLACKLIST);
2268     }
2269 
enableRssiPolling(boolean enabled)2270     public void enableRssiPolling(boolean enabled) {
2271         sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
2272     }
2273 
enableAllNetworks()2274     public void enableAllNetworks() {
2275         sendMessage(CMD_ENABLE_ALL_NETWORKS);
2276     }
2277 
2278     /**
2279      * Start filtering Multicast v4 packets
2280      */
startFilteringMulticastV4Packets()2281     public void startFilteringMulticastV4Packets() {
2282         mFilteringMulticastV4Packets.set(true);
2283         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
2284     }
2285 
2286     /**
2287      * Stop filtering Multicast v4 packets
2288      */
stopFilteringMulticastV4Packets()2289     public void stopFilteringMulticastV4Packets() {
2290         mFilteringMulticastV4Packets.set(false);
2291         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
2292     }
2293 
2294     /**
2295      * Start filtering Multicast v4 packets
2296      */
startFilteringMulticastV6Packets()2297     public void startFilteringMulticastV6Packets() {
2298         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
2299     }
2300 
2301     /**
2302      * Stop filtering Multicast v4 packets
2303      */
stopFilteringMulticastV6Packets()2304     public void stopFilteringMulticastV6Packets() {
2305         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
2306     }
2307 
2308     /**
2309      * Set high performance mode of operation.
2310      * Enabling would set active power mode and disable suspend optimizations;
2311      * disabling would set auto power mode and enable suspend optimizations
2312      *
2313      * @param enable true if enable, false otherwise
2314      */
setHighPerfModeEnabled(boolean enable)2315     public void setHighPerfModeEnabled(boolean enable) {
2316         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
2317     }
2318 
2319     /**
2320      * Set the country code
2321      *
2322      * @param countryCode following ISO 3166 format
2323      * @param persist     {@code true} if the setting should be remembered.
2324      */
setCountryCode(String countryCode, boolean persist)2325     public synchronized void setCountryCode(String countryCode, boolean persist) {
2326         // If it's a good country code, apply after the current
2327         // wifi connection is terminated; ignore resetting of code
2328         // for now (it is unclear what the chipset should do when
2329         // country code is reset)
2330 
2331         if (TextUtils.isEmpty(countryCode)) {
2332             log("Ignoring resetting of country code");
2333         } else {
2334             // if mCountryCodeSequence == 0, it is the first time to set country code, always set
2335             // else only when the new country code is different from the current one to set
2336             int countryCodeSequence = mCountryCodeSequence.get();
2337             if (countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) {
2338 
2339                 countryCodeSequence = mCountryCodeSequence.incrementAndGet();
2340                 mSetCountryCode = countryCode;
2341                 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0,
2342                         countryCode);
2343             }
2344 
2345             if (persist) {
2346                 Settings.Global.putString(mContext.getContentResolver(),
2347                         Settings.Global.WIFI_COUNTRY_CODE,
2348                         countryCode);
2349             }
2350         }
2351     }
2352 
2353     /**
2354      * Get Network object of current wifi network
2355      * @return Network object of current wifi network
2356      */
getCurrentNetwork()2357     public Network getCurrentNetwork() {
2358         if (mNetworkAgent != null) {
2359             return new Network(mNetworkAgent.netId);
2360         } else {
2361             return null;
2362         }
2363     }
2364 
2365     /**
2366      * Get the country code
2367      *
2368      * @param countryCode following ISO 3166 format
2369      */
getCountryCode()2370     public String getCountryCode() {
2371         return mSetCountryCode;
2372     }
2373 
2374 
2375     /**
2376      * Set the operational frequency band
2377      *
2378      * @param band
2379      * @param persist {@code true} if the setting should be remembered.
2380      */
setFrequencyBand(int band, boolean persist)2381     public void setFrequencyBand(int band, boolean persist) {
2382         if (persist) {
2383             Settings.Global.putInt(mContext.getContentResolver(),
2384                     Settings.Global.WIFI_FREQUENCY_BAND,
2385                     band);
2386         }
2387         sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
2388     }
2389 
2390     /**
2391      * Enable TDLS for a specific MAC address
2392      */
enableTdls(String remoteMacAddress, boolean enable)2393     public void enableTdls(String remoteMacAddress, boolean enable) {
2394         int enabler = enable ? 1 : 0;
2395         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
2396     }
2397 
2398     /**
2399      * Returns the operational frequency band
2400      */
getFrequencyBand()2401     public int getFrequencyBand() {
2402         return mFrequencyBand.get();
2403     }
2404 
2405     /**
2406      * Returns the wifi configuration file
2407      */
getConfigFile()2408     public String getConfigFile() {
2409         return mWifiConfigStore.getConfigFile();
2410     }
2411 
2412     /**
2413      * Send a message indicating bluetooth adapter connection state changed
2414      */
sendBluetoothAdapterStateChange(int state)2415     public void sendBluetoothAdapterStateChange(int state) {
2416         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
2417     }
2418 
2419     /**
2420      * Send a message indicating a package has been uninstalled.
2421      */
removeAppConfigs(String packageName, int uid)2422     public void removeAppConfigs(String packageName, int uid) {
2423         // Build partial AppInfo manually - package may not exist in database any more
2424         ApplicationInfo ai = new ApplicationInfo();
2425         ai.packageName = packageName;
2426         ai.uid = uid;
2427         sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai);
2428     }
2429 
2430     /**
2431      * Send a message indicating a user has been removed.
2432      */
removeUserConfigs(int userId)2433     public void removeUserConfigs(int userId) {
2434         sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId);
2435     }
2436 
2437     /**
2438      * Save configuration on supplicant
2439      *
2440      * @return {@code true} if the operation succeeds, {@code false} otherwise
2441      * <p/>
2442      * TODO: deprecate this
2443      */
syncSaveConfig(AsyncChannel channel)2444     public boolean syncSaveConfig(AsyncChannel channel) {
2445         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
2446         boolean result = (resultMsg.arg1 != FAILURE);
2447         resultMsg.recycle();
2448         return result;
2449     }
2450 
updateBatteryWorkSource(WorkSource newSource)2451     public void updateBatteryWorkSource(WorkSource newSource) {
2452         synchronized (mRunningWifiUids) {
2453             try {
2454                 if (newSource != null) {
2455                     mRunningWifiUids.set(newSource);
2456                 }
2457                 if (mIsRunning) {
2458                     if (mReportedRunning) {
2459                         // If the work source has changed since last time, need
2460                         // to remove old work from battery stats.
2461                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
2462                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
2463                                     mRunningWifiUids);
2464                             mLastRunningWifiUids.set(mRunningWifiUids);
2465                         }
2466                     } else {
2467                         // Now being started, report it.
2468                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
2469                         mLastRunningWifiUids.set(mRunningWifiUids);
2470                         mReportedRunning = true;
2471                     }
2472                 } else {
2473                     if (mReportedRunning) {
2474                         // Last reported we were running, time to stop.
2475                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
2476                         mLastRunningWifiUids.clear();
2477                         mReportedRunning = false;
2478                     }
2479                 }
2480                 mWakeLock.setWorkSource(newSource);
2481             } catch (RemoteException ignore) {
2482             }
2483         }
2484     }
2485 
2486     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2487     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2488         super.dump(fd, pw, args);
2489         mSupplicantStateTracker.dump(fd, pw, args);
2490         pw.println("mLinkProperties " + mLinkProperties);
2491         pw.println("mWifiInfo " + mWifiInfo);
2492         pw.println("mDhcpResults " + mDhcpResults);
2493         pw.println("mNetworkInfo " + mNetworkInfo);
2494         pw.println("mLastSignalLevel " + mLastSignalLevel);
2495         pw.println("mLastBssid " + mLastBssid);
2496         pw.println("mLastNetworkId " + mLastNetworkId);
2497         pw.println("mOperationalMode " + mOperationalMode);
2498         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
2499         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2500         pw.println("Supplicant status " + mWifiNative.status(true));
2501         pw.println("mLegacyPnoEnabled " + mLegacyPnoEnabled);
2502         pw.println("mSetCountryCode " + mSetCountryCode);
2503         pw.println("mDriverSetCountryCode " + mDriverSetCountryCode);
2504         pw.println("mConnectedModeGScanOffloadStarted " + mConnectedModeGScanOffloadStarted);
2505         pw.println("mGScanPeriodMilli " + mGScanPeriodMilli);
2506         if (mWhiteListedSsids != null && mWhiteListedSsids.length > 0) {
2507             pw.println("SSID whitelist :" );
2508             for (int i=0; i < mWhiteListedSsids.length; i++) {
2509                 pw.println("       " + mWhiteListedSsids[i]);
2510             }
2511         }
2512         mNetworkFactory.dump(fd, pw, args);
2513         mUntrustedNetworkFactory.dump(fd, pw, args);
2514         pw.println();
2515         mWifiConfigStore.dump(fd, pw, args);
2516         pw.println();
2517         mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_USER_ACTION);
2518         mWifiLogger.dump(fd, pw, args);
2519     }
2520 
2521     /**
2522      * ******************************************************
2523      * Internal private functions
2524      * ******************************************************
2525      */
2526 
logStateAndMessage(Message message, String state)2527     private void logStateAndMessage(Message message, String state) {
2528         messageHandlingStatus = 0;
2529         if (mLogMessages) {
2530             //long now = SystemClock.elapsedRealtimeNanos();
2531             //String ts = String.format("[%,d us]", now/1000);
2532 
2533             logd(" " + state + " " + getLogRecString(message));
2534         }
2535     }
2536 
2537     /**
2538      * helper, prints the milli time since boot wi and w/o suspended time
2539      */
printTime()2540     String printTime() {
2541         StringBuilder sb = new StringBuilder();
2542         sb.append(" rt=").append(SystemClock.uptimeMillis());
2543         sb.append("/").append(SystemClock.elapsedRealtime());
2544         return sb.toString();
2545     }
2546 
2547     /**
2548      * Return the additional string to be logged by LogRec, default
2549      *
2550      * @param msg that was processed
2551      * @return information to be logged as a String
2552      */
getLogRecString(Message msg)2553     protected String getLogRecString(Message msg) {
2554         WifiConfiguration config;
2555         Long now;
2556         String report;
2557         String key;
2558         StringBuilder sb = new StringBuilder();
2559         if (mScreenOn) {
2560             sb.append("!");
2561         }
2562         if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
2563             sb.append("(").append(messageHandlingStatus).append(")");
2564         }
2565         sb.append(smToString(msg));
2566         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
2567             sb.append(" uid=" + msg.sendingUid);
2568         }
2569         sb.append(" ").append(printTime());
2570         switch (msg.what) {
2571             case CMD_STARTED_GSCAN_DBG:
2572             case CMD_STARTED_PNO_DBG:
2573                 sb.append(" ");
2574                 sb.append(Integer.toString(msg.arg1));
2575                 sb.append(" ");
2576                 sb.append(Integer.toString(msg.arg2));
2577                 if (msg.obj != null) {
2578                     sb.append(" " + (String)msg.obj);
2579                 }
2580                 break;
2581             case CMD_RESTART_AUTOJOIN_OFFLOAD:
2582                 sb.append(" ");
2583                 sb.append(Integer.toString(msg.arg1));
2584                 sb.append(" ");
2585                 sb.append(Integer.toString(msg.arg2));
2586                 sb.append("/").append(Integer.toString(mRestartAutoJoinOffloadCounter));
2587                 if (msg.obj != null) {
2588                     sb.append(" " + (String)msg.obj);
2589                 }
2590                 break;
2591             case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
2592                 sb.append(" ");
2593                 sb.append(Integer.toString(msg.arg1));
2594                 sb.append(" ");
2595                 sb.append(Integer.toString(msg.arg2));
2596                 sb.append(" halAllowed=").append(useHalBasedAutoJoinOffload());
2597                 sb.append(" scanAllowed=").append(allowFullBandScanAndAssociated());
2598                 sb.append(" autojoinAllowed=");
2599                 sb.append(mWifiConfigStore.enableAutoJoinWhenAssociated.get());
2600                 sb.append(" withTraffic=").append(getAllowScansWithTraffic());
2601                 sb.append(" tx=").append(mWifiInfo.txSuccessRate);
2602                 sb.append("/").append(mWifiConfigStore.maxTxPacketForFullScans);
2603                 sb.append(" rx=").append(mWifiInfo.rxSuccessRate);
2604                 sb.append("/").append(mWifiConfigStore.maxRxPacketForFullScans);
2605                 sb.append(" -> ").append(mConnectedModeGScanOffloadStarted);
2606                 break;
2607             case CMD_PNO_NETWORK_FOUND:
2608                 sb.append(" ");
2609                 sb.append(Integer.toString(msg.arg1));
2610                 sb.append(" ");
2611                 sb.append(Integer.toString(msg.arg2));
2612                 if (msg.obj != null) {
2613                     ScanResult[] results = (ScanResult[])msg.obj;
2614                     for (int i = 0; i < results.length; i++) {
2615                        sb.append(" ").append(results[i].SSID).append(" ");
2616                        sb.append(results[i].frequency);
2617                        sb.append(" ").append(results[i].level);
2618                     }
2619                 }
2620                 break;
2621             case CMD_START_SCAN:
2622                 now = System.currentTimeMillis();
2623                 sb.append(" ");
2624                 sb.append(Integer.toString(msg.arg1));
2625                 sb.append(" ");
2626                 sb.append(Integer.toString(msg.arg2));
2627                 sb.append(" ic=");
2628                 sb.append(Integer.toString(sScanAlarmIntentCount));
2629                 if (msg.obj != null) {
2630                     Bundle bundle = (Bundle) msg.obj;
2631                     Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
2632                     if (request != 0) {
2633                         sb.append(" proc(ms):").append(now - request);
2634                     }
2635                 }
2636                 if (mIsScanOngoing) sb.append(" onGoing");
2637                 if (mIsFullScanOngoing) sb.append(" full");
2638                 if (lastStartScanTimeStamp != 0) {
2639                     sb.append(" started:").append(lastStartScanTimeStamp);
2640                     sb.append(",").append(now - lastStartScanTimeStamp);
2641                 }
2642                 if (lastScanDuration != 0) {
2643                     sb.append(" dur:").append(lastScanDuration);
2644                 }
2645                 sb.append(" cnt=").append(mDelayedScanCounter);
2646                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2647                 sb.append(" f=").append(mWifiInfo.getFrequency());
2648                 sb.append(" sc=").append(mWifiInfo.score);
2649                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2650                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2651                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2652                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2653                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2654                 if (lastScanFreqs != null) {
2655                     sb.append(" list=").append(lastScanFreqs);
2656                 } else {
2657                     sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli);
2658                 }
2659                 report = reportOnTime();
2660                 if (report != null) {
2661                     sb.append(" ").append(report);
2662                 }
2663                 break;
2664             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2665                 sb.append(" ");
2666                 sb.append(Integer.toString(msg.arg1));
2667                 sb.append(" ");
2668                 sb.append(Integer.toString(msg.arg2));
2669                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
2670                 if (stateChangeResult != null) {
2671                     sb.append(stateChangeResult.toString());
2672                 }
2673                 break;
2674             case WifiManager.SAVE_NETWORK:
2675             case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
2676                 sb.append(" ");
2677                 sb.append(Integer.toString(msg.arg1));
2678                 sb.append(" ");
2679                 sb.append(Integer.toString(msg.arg2));
2680                 if (lastSavedConfigurationAttempt != null) {
2681                     sb.append(" ").append(lastSavedConfigurationAttempt.configKey());
2682                     sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId);
2683                     if (lastSavedConfigurationAttempt.hiddenSSID) {
2684                         sb.append(" hidden");
2685                     }
2686                     if (lastSavedConfigurationAttempt.preSharedKey != null
2687                             && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) {
2688                         sb.append(" hasPSK");
2689                     }
2690                     if (lastSavedConfigurationAttempt.ephemeral) {
2691                         sb.append(" ephemeral");
2692                     }
2693                     if (lastSavedConfigurationAttempt.selfAdded) {
2694                         sb.append(" selfAdded");
2695                     }
2696                     sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid);
2697                     sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid);
2698                 }
2699                 break;
2700             case WifiManager.FORGET_NETWORK:
2701                 sb.append(" ");
2702                 sb.append(Integer.toString(msg.arg1));
2703                 sb.append(" ");
2704                 sb.append(Integer.toString(msg.arg2));
2705                 if (lastForgetConfigurationAttempt != null) {
2706                     sb.append(" ").append(lastForgetConfigurationAttempt.configKey());
2707                     sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId);
2708                     if (lastForgetConfigurationAttempt.hiddenSSID) {
2709                         sb.append(" hidden");
2710                     }
2711                     if (lastForgetConfigurationAttempt.preSharedKey != null) {
2712                         sb.append(" hasPSK");
2713                     }
2714                     if (lastForgetConfigurationAttempt.ephemeral) {
2715                         sb.append(" ephemeral");
2716                     }
2717                     if (lastForgetConfigurationAttempt.selfAdded) {
2718                         sb.append(" selfAdded");
2719                     }
2720                     sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid);
2721                     sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid);
2722                     sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus);
2723                 }
2724                 break;
2725             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2726                 sb.append(" ");
2727                 sb.append(Integer.toString(msg.arg1));
2728                 sb.append(" ");
2729                 sb.append(Integer.toString(msg.arg2));
2730                 String bssid = (String) msg.obj;
2731                 if (bssid != null && bssid.length() > 0) {
2732                     sb.append(" ");
2733                     sb.append(bssid);
2734                 }
2735                 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
2736                 break;
2737             case WifiMonitor.SCAN_RESULTS_EVENT:
2738                 sb.append(" ");
2739                 sb.append(Integer.toString(msg.arg1));
2740                 sb.append(" ");
2741                 sb.append(Integer.toString(msg.arg2));
2742                 if (mScanResults != null) {
2743                     sb.append(" found=");
2744                     sb.append(mScanResults.size());
2745                 }
2746                 sb.append(" known=").append(mNumScanResultsKnown);
2747                 sb.append(" got=").append(mNumScanResultsReturned);
2748                 if (lastScanDuration != 0) {
2749                     sb.append(" dur:").append(lastScanDuration);
2750                 }
2751                 if (mOnTime != 0) {
2752                     sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan);
2753                     sb.append(",").append(mOnTime);
2754                 }
2755                 if (mTxTime != 0) {
2756                     sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan);
2757                     sb.append(",").append(mTxTime);
2758                 }
2759                 if (mRxTime != 0) {
2760                     sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan);
2761                     sb.append(",").append(mRxTime);
2762                 }
2763                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2764                 sb.append(String.format(" con=%d", mConnectionRequests));
2765                 key = mWifiConfigStore.getLastSelectedConfiguration();
2766                 if (key != null) {
2767                     sb.append(" last=").append(key);
2768                 }
2769                 break;
2770             case WifiMonitor.SCAN_FAILED_EVENT:
2771                 break;
2772             case WifiMonitor.NETWORK_CONNECTION_EVENT:
2773                 sb.append(" ");
2774                 sb.append(Integer.toString(msg.arg1));
2775                 sb.append(" ");
2776                 sb.append(Integer.toString(msg.arg2));
2777                 sb.append(" ").append(mLastBssid);
2778                 sb.append(" nid=").append(mLastNetworkId);
2779                 config = getCurrentWifiConfiguration();
2780                 if (config != null) {
2781                     sb.append(" ").append(config.configKey());
2782                 }
2783                 key = mWifiConfigStore.getLastSelectedConfiguration();
2784                 if (key != null) {
2785                     sb.append(" last=").append(key);
2786                 }
2787                 break;
2788             case CMD_TARGET_BSSID:
2789             case CMD_ASSOCIATED_BSSID:
2790                 sb.append(" ");
2791                 sb.append(Integer.toString(msg.arg1));
2792                 sb.append(" ");
2793                 sb.append(Integer.toString(msg.arg2));
2794                 if (msg.obj != null) {
2795                     sb.append(" BSSID=").append((String) msg.obj);
2796                 }
2797                 if (mTargetRoamBSSID != null) {
2798                     sb.append(" Target=").append(mTargetRoamBSSID);
2799                 }
2800                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
2801                 break;
2802             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2803                 if (msg.obj != null) {
2804                     sb.append(" ").append((String) msg.obj);
2805                 }
2806                 sb.append(" nid=").append(msg.arg1);
2807                 sb.append(" reason=").append(msg.arg2);
2808                 if (mLastBssid != null) {
2809                     sb.append(" lastbssid=").append(mLastBssid);
2810                 }
2811                 if (mWifiInfo.getFrequency() != -1) {
2812                     sb.append(" freq=").append(mWifiInfo.getFrequency());
2813                     sb.append(" rssi=").append(mWifiInfo.getRssi());
2814                 }
2815                 if (linkDebouncing) {
2816                     sb.append(" debounce");
2817                 }
2818                 break;
2819             case WifiMonitor.SSID_TEMP_DISABLED:
2820             case WifiMonitor.SSID_REENABLED:
2821                 sb.append(" nid=").append(msg.arg1);
2822                 if (msg.obj != null) {
2823                     sb.append(" ").append((String) msg.obj);
2824                 }
2825                 config = getCurrentWifiConfiguration();
2826                 if (config != null) {
2827                     sb.append(" cur=").append(config.configKey());
2828                     sb.append(" ajst=").append(config.autoJoinStatus);
2829                     if (config.selfAdded) {
2830                         sb.append(" selfAdded");
2831                     }
2832                     if (config.status != 0) {
2833                         sb.append(" st=").append(config.status);
2834                         sb.append(" rs=").append(config.disableReason);
2835                     }
2836                     if (config.lastConnected != 0) {
2837                         now = System.currentTimeMillis();
2838                         sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)");
2839                     }
2840                     if (mLastBssid != null) {
2841                         sb.append(" lastbssid=").append(mLastBssid);
2842                     }
2843                     if (mWifiInfo.getFrequency() != -1) {
2844                         sb.append(" freq=").append(mWifiInfo.getFrequency());
2845                         sb.append(" rssi=").append(mWifiInfo.getRssi());
2846                         sb.append(" bssid=").append(mWifiInfo.getBSSID());
2847                     }
2848                 }
2849                 break;
2850             case CMD_RSSI_POLL:
2851             case CMD_UNWANTED_NETWORK:
2852             case WifiManager.RSSI_PKTCNT_FETCH:
2853                 sb.append(" ");
2854                 sb.append(Integer.toString(msg.arg1));
2855                 sb.append(" ");
2856                 sb.append(Integer.toString(msg.arg2));
2857                 if (mWifiInfo.getSSID() != null)
2858                     if (mWifiInfo.getSSID() != null)
2859                         sb.append(" ").append(mWifiInfo.getSSID());
2860                 if (mWifiInfo.getBSSID() != null)
2861                     sb.append(" ").append(mWifiInfo.getBSSID());
2862                 sb.append(" rssi=").append(mWifiInfo.getRssi());
2863                 sb.append(" f=").append(mWifiInfo.getFrequency());
2864                 sb.append(" sc=").append(mWifiInfo.score);
2865                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2866                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2867                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2868                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2869                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2870                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
2871                 report = reportOnTime();
2872                 if (report != null) {
2873                     sb.append(" ").append(report);
2874                 }
2875                 if (wifiScoringReport != null) {
2876                     sb.append(wifiScoringReport);
2877                 }
2878                 if (mConnectedModeGScanOffloadStarted) {
2879                     sb.append(" offload-started periodMilli " + mGScanPeriodMilli);
2880                 } else {
2881                     sb.append(" offload-stopped");
2882                 }
2883                 break;
2884             case CMD_AUTO_CONNECT:
2885             case WifiManager.CONNECT_NETWORK:
2886                 sb.append(" ");
2887                 sb.append(Integer.toString(msg.arg1));
2888                 sb.append(" ");
2889                 sb.append(Integer.toString(msg.arg2));
2890                 config = (WifiConfiguration) msg.obj;
2891                 if (config != null) {
2892                     sb.append(" ").append(config.configKey());
2893                     if (config.visibility != null) {
2894                         sb.append(" ").append(config.visibility.toString());
2895                     }
2896                 }
2897                 if (mTargetRoamBSSID != null) {
2898                     sb.append(" ").append(mTargetRoamBSSID);
2899                 }
2900                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
2901                 config = getCurrentWifiConfiguration();
2902                 if (config != null) {
2903                     sb.append(config.configKey());
2904                     if (config.visibility != null) {
2905                         sb.append(" ").append(config.visibility.toString());
2906                     }
2907                 }
2908                 break;
2909             case CMD_AUTO_ROAM:
2910                 sb.append(" ");
2911                 sb.append(Integer.toString(msg.arg1));
2912                 sb.append(" ");
2913                 sb.append(Integer.toString(msg.arg2));
2914                 ScanResult result = (ScanResult) msg.obj;
2915                 if (result != null) {
2916                     now = System.currentTimeMillis();
2917                     sb.append(" bssid=").append(result.BSSID);
2918                     sb.append(" rssi=").append(result.level);
2919                     sb.append(" freq=").append(result.frequency);
2920                     if (result.seen > 0 && result.seen < now) {
2921                         sb.append(" seen=").append(now - result.seen);
2922                     } else {
2923                         // Somehow the timestamp for this scan result is inconsistent
2924                         sb.append(" !seen=").append(result.seen);
2925                     }
2926                 }
2927                 if (mTargetRoamBSSID != null) {
2928                     sb.append(" ").append(mTargetRoamBSSID);
2929                 }
2930                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
2931                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
2932                 break;
2933             case CMD_ADD_OR_UPDATE_NETWORK:
2934                 sb.append(" ");
2935                 sb.append(Integer.toString(msg.arg1));
2936                 sb.append(" ");
2937                 sb.append(Integer.toString(msg.arg2));
2938                 if (msg.obj != null) {
2939                     config = (WifiConfiguration) msg.obj;
2940                     sb.append(" ").append(config.configKey());
2941                     sb.append(" prio=").append(config.priority);
2942                     sb.append(" status=").append(config.status);
2943                     if (config.BSSID != null) {
2944                         sb.append(" ").append(config.BSSID);
2945                     }
2946                     WifiConfiguration curConfig = getCurrentWifiConfiguration();
2947                     if (curConfig != null) {
2948                         if (curConfig.configKey().equals(config.configKey())) {
2949                             sb.append(" is current");
2950                         } else {
2951                             sb.append(" current=").append(curConfig.configKey());
2952                             sb.append(" prio=").append(curConfig.priority);
2953                             sb.append(" status=").append(curConfig.status);
2954                         }
2955                     }
2956                 }
2957                 break;
2958             case WifiManager.DISABLE_NETWORK:
2959             case CMD_ENABLE_NETWORK:
2960                 sb.append(" ");
2961                 sb.append(Integer.toString(msg.arg1));
2962                 sb.append(" ");
2963                 sb.append(Integer.toString(msg.arg2));
2964                 key = mWifiConfigStore.getLastSelectedConfiguration();
2965                 if (key != null) {
2966                     sb.append(" last=").append(key);
2967                 }
2968                 config = mWifiConfigStore.getWifiConfiguration(msg.arg1);
2969                 if (config != null && (key == null || !config.configKey().equals(key))) {
2970                     sb.append(" target=").append(key);
2971                 }
2972                 break;
2973             case CMD_GET_CONFIGURED_NETWORKS:
2974                 sb.append(" ");
2975                 sb.append(Integer.toString(msg.arg1));
2976                 sb.append(" ");
2977                 sb.append(Integer.toString(msg.arg2));
2978                 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize());
2979                 break;
2980             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2981                 sb.append(" ");
2982                 sb.append(Integer.toString(msg.arg1));
2983                 sb.append(" ");
2984                 sb.append(Integer.toString(msg.arg2));
2985                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
2986                 sb.append(",").append(mWifiInfo.txBad);
2987                 sb.append(",").append(mWifiInfo.txRetries);
2988                 break;
2989             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2990                 sb.append(" ");
2991                 sb.append(Integer.toString(msg.arg1));
2992                 sb.append(" ");
2993                 sb.append(Integer.toString(msg.arg2));
2994                 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2995                     sb.append(" OK ");
2996                 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2997                     sb.append(" FAIL ");
2998                 }
2999                 if (mLinkProperties != null) {
3000                     if (mLinkProperties.hasIPv4Address()) {
3001                         sb.append(" v4");
3002                     }
3003                     if (mLinkProperties.hasGlobalIPv6Address()) {
3004                         sb.append(" v6");
3005                     }
3006                     if (mLinkProperties.hasIPv4DefaultRoute()) {
3007                         sb.append(" v4r");
3008                     }
3009                     if (mLinkProperties.hasIPv6DefaultRoute()) {
3010                         sb.append(" v6r");
3011                     }
3012                     if (mLinkProperties.hasIPv4DnsServer()) {
3013                         sb.append(" v4dns");
3014                     }
3015                     if (mLinkProperties.hasIPv6DnsServer()) {
3016                         sb.append(" v6dns");
3017                     }
3018                 }
3019                 break;
3020             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
3021                 sb.append(" ");
3022                 sb.append(Integer.toString(msg.arg1));
3023                 sb.append(" ");
3024                 sb.append(Integer.toString(msg.arg2));
3025                 if (msg.obj != null) {
3026                     NetworkInfo info = (NetworkInfo) msg.obj;
3027                     NetworkInfo.State state = info.getState();
3028                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
3029                     if (state != null) {
3030                         sb.append(" st=").append(state);
3031                     }
3032                     if (detailedState != null) {
3033                         sb.append("/").append(detailedState);
3034                     }
3035                 }
3036                 break;
3037             case CMD_IP_CONFIGURATION_LOST:
3038                 int count = -1;
3039                 WifiConfiguration c = getCurrentWifiConfiguration();
3040                 if (c != null) count = c.numIpConfigFailures;
3041                 sb.append(" ");
3042                 sb.append(Integer.toString(msg.arg1));
3043                 sb.append(" ");
3044                 sb.append(Integer.toString(msg.arg2));
3045                 sb.append(" failures: ");
3046                 sb.append(Integer.toString(count));
3047                 sb.append("/");
3048                 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries()));
3049                 if (mWifiInfo.getBSSID() != null) {
3050                     sb.append(" ").append(mWifiInfo.getBSSID());
3051                 }
3052                 if (c != null) {
3053                     ScanDetailCache scanDetailCache =
3054                             mWifiConfigStore.getScanDetailCache(c);
3055                     if (scanDetailCache != null) {
3056                         for (ScanDetail sd : scanDetailCache.values()) {
3057                             ScanResult r = sd.getScanResult();
3058                             if (r.BSSID.equals(mWifiInfo.getBSSID())) {
3059                                 sb.append(" ipfail=").append(r.numIpConfigFailures);
3060                                 sb.append(",st=").append(r.autoJoinStatus);
3061                             }
3062                         }
3063                     }
3064                     sb.append(" -> ajst=").append(c.autoJoinStatus);
3065                     sb.append(" ").append(c.disableReason);
3066                     sb.append(" txpkts=").append(mWifiInfo.txSuccess);
3067                     sb.append(",").append(mWifiInfo.txBad);
3068                     sb.append(",").append(mWifiInfo.txRetries);
3069                 }
3070                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
3071                 break;
3072             case CMD_UPDATE_LINKPROPERTIES:
3073                 sb.append(" ");
3074                 sb.append(Integer.toString(msg.arg1));
3075                 sb.append(" ");
3076                 sb.append(Integer.toString(msg.arg2));
3077                 if (mLinkProperties != null) {
3078                     if (mLinkProperties.hasIPv4Address()) {
3079                         sb.append(" v4");
3080                     }
3081                     if (mLinkProperties.hasGlobalIPv6Address()) {
3082                         sb.append(" v6");
3083                     }
3084                     if (mLinkProperties.hasIPv4DefaultRoute()) {
3085                         sb.append(" v4r");
3086                     }
3087                     if (mLinkProperties.hasIPv6DefaultRoute()) {
3088                         sb.append(" v6r");
3089                     }
3090                     if (mLinkProperties.hasIPv4DnsServer()) {
3091                         sb.append(" v4dns");
3092                     }
3093                     if (mLinkProperties.hasIPv6DnsServer()) {
3094                         sb.append(" v6dns");
3095                     }
3096                 }
3097                 break;
3098             case CMD_IP_REACHABILITY_LOST:
3099                 if (msg.obj != null) {
3100                     sb.append(" ").append((String) msg.obj);
3101                 }
3102                 break;
3103             case CMD_SET_COUNTRY_CODE:
3104                 sb.append(" ");
3105                 sb.append(Integer.toString(msg.arg1));
3106                 sb.append(" ");
3107                 sb.append(Integer.toString(msg.arg2));
3108                 if (msg.obj != null) {
3109                     sb.append(" ").append((String) msg.obj);
3110                 }
3111                 break;
3112             case CMD_ROAM_WATCHDOG_TIMER:
3113                 sb.append(" ");
3114                 sb.append(Integer.toString(msg.arg1));
3115                 sb.append(" ");
3116                 sb.append(Integer.toString(msg.arg2));
3117                 sb.append(" cur=").append(roamWatchdogCount);
3118                 break;
3119             case CMD_DISCONNECTING_WATCHDOG_TIMER:
3120                 sb.append(" ");
3121                 sb.append(Integer.toString(msg.arg1));
3122                 sb.append(" ");
3123                 sb.append(Integer.toString(msg.arg2));
3124                 sb.append(" cur=").append(disconnectingWatchdogCount);
3125                 break;
3126             default:
3127                 sb.append(" ");
3128                 sb.append(Integer.toString(msg.arg1));
3129                 sb.append(" ");
3130                 sb.append(Integer.toString(msg.arg2));
3131                 break;
3132         }
3133 
3134         return sb.toString();
3135     }
3136 
stopPnoOffload()3137     private void stopPnoOffload() {
3138 
3139         // clear the PNO list
3140         if (!WifiNative.setPnoList(null, WifiStateMachine.this)) {
3141             Log.e(TAG, "Failed to stop pno");
3142         }
3143 
3144     }
3145 
3146 
configureSsidWhiteList()3147     private boolean configureSsidWhiteList() {
3148 
3149         mWhiteListedSsids = mWifiConfigStore.getWhiteListedSsids(getCurrentWifiConfiguration());
3150         if (mWhiteListedSsids == null || mWhiteListedSsids.length == 0) {
3151             return true;
3152         }
3153 
3154        if (!WifiNative.setSsidWhitelist(mWhiteListedSsids)) {
3155             loge("configureSsidWhiteList couldnt program SSID list, size "
3156                     + mWhiteListedSsids.length);
3157             return false;
3158         }
3159 
3160         logd("configureSsidWhiteList success");
3161         return true;
3162     }
3163 
3164     // In associated more, lazy roam will be looking for 5GHz roam candidate
configureLazyRoam()3165     private boolean configureLazyRoam() {
3166         boolean status;
3167         if (!useHalBasedAutoJoinOffload()) return false;
3168 
3169         WifiNative.WifiLazyRoamParams params = mWifiNative.new WifiLazyRoamParams();
3170         params.A_band_boost_threshold = mWifiConfigStore.bandPreferenceBoostThreshold5.get();
3171         params.A_band_penalty_threshold = mWifiConfigStore.bandPreferencePenaltyThreshold5.get();
3172         params.A_band_boost_factor = mWifiConfigStore.bandPreferenceBoostFactor5;
3173         params.A_band_penalty_factor = mWifiConfigStore.bandPreferencePenaltyFactor5;
3174         params.A_band_max_boost = 65;
3175         params.lazy_roam_hysteresis = 25;
3176         params.alert_roam_rssi_trigger = -75;
3177 
3178         if (DBG) {
3179             Log.e(TAG, "configureLazyRoam " + params.toString());
3180         }
3181 
3182         if (!WifiNative.setLazyRoam(true, params)) {
3183 
3184             Log.e(TAG, "configureLazyRoam couldnt program params");
3185 
3186             return false;
3187         }
3188         if (DBG) {
3189             Log.e(TAG, "configureLazyRoam success");
3190         }
3191         return true;
3192     }
3193 
3194     // In associated more, lazy roam will be looking for 5GHz roam candidate
stopLazyRoam()3195     private boolean stopLazyRoam() {
3196         boolean status;
3197         if (!useHalBasedAutoJoinOffload()) return false;
3198         if (DBG) {
3199             Log.e(TAG, "stopLazyRoam");
3200         }
3201         return WifiNative.setLazyRoam(false, null);
3202     }
3203 
startGScanConnectedModeOffload(String reason)3204     private boolean startGScanConnectedModeOffload(String reason) {
3205         if (DBG) {
3206             if (reason == null) {
3207                 reason = "";
3208             }
3209             logd("startGScanConnectedModeOffload " + reason);
3210         }
3211         stopGScan("startGScanConnectedModeOffload " + reason);
3212         if (!mScreenOn) return false;
3213 
3214         if (USE_PAUSE_SCANS) {
3215             mWifiNative.pauseScan();
3216         }
3217         mPnoEnabled = configurePno();
3218         if (mPnoEnabled == false) {
3219             if (USE_PAUSE_SCANS) {
3220                 mWifiNative.restartScan();
3221             }
3222             return false;
3223         }
3224         mLazyRoamEnabled = configureLazyRoam();
3225         if (mLazyRoamEnabled == false) {
3226             if (USE_PAUSE_SCANS) {
3227                 mWifiNative.restartScan();
3228             }
3229             return false;
3230         }
3231         if (mWifiConfigStore.getLastSelectedConfiguration() == null) {
3232             configureSsidWhiteList();
3233         }
3234         if (!startConnectedGScan(reason)) {
3235             if (USE_PAUSE_SCANS) {
3236                 mWifiNative.restartScan();
3237             }
3238             return false;
3239         }
3240         if (USE_PAUSE_SCANS) {
3241             mWifiNative.restartScan();
3242         }
3243         mConnectedModeGScanOffloadStarted = true;
3244         if (DBG) {
3245             logd("startGScanConnectedModeOffload success");
3246         }
3247         return true;
3248     }
3249 
startGScanDisconnectedModeOffload(String reason)3250     private boolean startGScanDisconnectedModeOffload(String reason) {
3251         if (DBG) {
3252             logd("startGScanDisconnectedModeOffload " + reason);
3253         }
3254         stopGScan("startGScanDisconnectedModeOffload " + reason);
3255         if (USE_PAUSE_SCANS) {
3256             mWifiNative.pauseScan();
3257         }
3258         mPnoEnabled = configurePno();
3259         if (mPnoEnabled == false) {
3260             if (USE_PAUSE_SCANS) {
3261                 mWifiNative.restartScan();
3262             }
3263             return false;
3264         }
3265         if (!startDisconnectedGScan(reason)) {
3266             if (USE_PAUSE_SCANS) {
3267                 mWifiNative.restartScan();
3268             }
3269             return false;
3270         }
3271         if (USE_PAUSE_SCANS) {
3272             mWifiNative.restartScan();
3273         }
3274         return true;
3275     }
3276 
configurePno()3277     private boolean configurePno() {
3278         if (!useHalBasedAutoJoinOffload()) return false;
3279 
3280         if (mWifiScanner == null) {
3281             log("configurePno: mWifiScanner is null ");
3282             return true;
3283         }
3284 
3285         List<WifiNative.WifiPnoNetwork> llist
3286                 = mWifiAutoJoinController.getPnoList(getCurrentWifiConfiguration());
3287         if (llist == null || llist.size() == 0) {
3288             stopPnoOffload();
3289             log("configurePno: empty PNO list ");
3290             return true;
3291         }
3292         if (DBG) {
3293             log("configurePno: got llist size " + llist.size());
3294         }
3295 
3296         // first program the network we want to look for thru the pno API
3297         WifiNative.WifiPnoNetwork list[]
3298                 = (WifiNative.WifiPnoNetwork[]) llist.toArray(new WifiNative.WifiPnoNetwork[0]);
3299 
3300         if (!WifiNative.setPnoList(list, WifiStateMachine.this)) {
3301             Log.e(TAG, "Failed to set pno, length = " + list.length);
3302             return false;
3303         }
3304 
3305         if (true) {
3306             StringBuilder sb = new StringBuilder();
3307             for (WifiNative.WifiPnoNetwork network : list) {
3308                 sb.append("[").append(network.SSID).append(" auth=").append(network.auth);
3309                 sb.append(" flags=");
3310                 sb.append(network.flags).append(" rssi").append(network.rssi_threshold);
3311                 sb.append("] ");
3312 
3313             }
3314             sendMessage(CMD_STARTED_PNO_DBG, 1, (int)mGScanPeriodMilli, sb.toString());
3315         }
3316         return true;
3317     }
3318 
3319     final static int DISCONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
3320     final static int CONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
3321 
startConnectedGScan(String reason)3322     private boolean startConnectedGScan(String reason) {
3323         // send a scan background request so as to kick firmware
3324         // 5GHz roaming and autojoin
3325         // We do this only if screen is on
3326         WifiScanner.ScanSettings settings;
3327 
3328         if (mPnoEnabled || mLazyRoamEnabled) {
3329             settings = new WifiScanner.ScanSettings();
3330             settings.band = WifiScanner.WIFI_BAND_BOTH;
3331             long now = System.currentTimeMillis();
3332 
3333             if (!mScreenOn  || (mGScanStartTimeMilli!= 0 && now > mGScanStartTimeMilli
3334                     && ((now - mGScanStartTimeMilli) > CONNECTED_SHORT_SCANS_DURATION_MILLI))) {
3335                 settings.periodInMs = mWifiConfigStore.wifiAssociatedLongScanIntervalMilli.get();
3336             } else {
3337                 mGScanStartTimeMilli = now;
3338                 settings.periodInMs = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
3339                 // if we start offload with short interval, then reconfigure it after a given
3340                 // duration of time so as to reduce the scan frequency
3341                 int delay = 30 * 1000 + CONNECTED_SHORT_SCANS_DURATION_MILLI;
3342                 sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
3343                         mRestartAutoJoinOffloadCounter, " startConnectedGScan " + reason,
3344                         (long)delay);
3345                 mRestartAutoJoinOffloadCounter++;
3346             }
3347             mGScanPeriodMilli = settings.periodInMs;
3348             settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
3349             if (DBG) {
3350                 log("startConnectedScan: settings band="+ settings.band
3351                         + " period=" + settings.periodInMs);
3352             }
3353 
3354             mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
3355             if (true) {
3356                 sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
3357             }
3358         }
3359         return true;
3360     }
3361 
startDisconnectedGScan(String reason)3362     private boolean startDisconnectedGScan(String reason) {
3363         // send a scan background request so as to kick firmware
3364         // PNO
3365         // This is done in both screen On and screen Off modes
3366         WifiScanner.ScanSettings settings;
3367 
3368         if (mWifiScanner == null) {
3369             log("startDisconnectedGScan: no wifi scanner");
3370             return false;
3371         }
3372 
3373         if (mPnoEnabled || mLazyRoamEnabled) {
3374             settings = new WifiScanner.ScanSettings();
3375             settings.band = WifiScanner.WIFI_BAND_BOTH;
3376             long now = System.currentTimeMillis();
3377 
3378 
3379             if (!mScreenOn  || (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
3380                     && ((now - mGScanStartTimeMilli) > DISCONNECTED_SHORT_SCANS_DURATION_MILLI))) {
3381                 settings.periodInMs = mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get();
3382             } else {
3383                 settings.periodInMs = mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get();
3384                 mGScanStartTimeMilli = now;
3385                 // if we start offload with short interval, then reconfigure it after a given
3386                 // duration of time so as to reduce the scan frequency
3387                 int delay = 30 * 1000 + DISCONNECTED_SHORT_SCANS_DURATION_MILLI;
3388                 sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
3389                         mRestartAutoJoinOffloadCounter, " startDisconnectedGScan " + reason,
3390                         (long)delay);
3391                 mRestartAutoJoinOffloadCounter++;
3392             }
3393             mGScanPeriodMilli = settings.periodInMs;
3394             settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
3395             if (DBG) {
3396                 log("startDisconnectedScan: settings band="+ settings.band
3397                         + " period=" + settings.periodInMs);
3398             }
3399             mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
3400             if (true) {
3401                 sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
3402             }
3403         }
3404         return true;
3405     }
3406 
stopGScan(String reason)3407     private boolean stopGScan(String reason) {
3408         mGScanStartTimeMilli = 0;
3409         mGScanPeriodMilli = 0;
3410         if (mWifiScanner != null) {
3411             mWifiScanner.stopBackgroundScan(mWifiScanListener);
3412         }
3413         mConnectedModeGScanOffloadStarted = false;
3414         if (true) {
3415             sendMessage(CMD_STARTED_GSCAN_DBG, 0, 0, reason);
3416         }
3417         return true;
3418     }
3419 
handleScreenStateChanged(boolean screenOn)3420     private void handleScreenStateChanged(boolean screenOn) {
3421         mScreenOn = screenOn;
3422         if (PDBG) {
3423             logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
3424                     + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
3425                     + " state " + getCurrentState().getName()
3426                     + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
3427         }
3428         enableRssiPolling(screenOn);
3429         if (screenOn) enableAllNetworks();
3430         if (mUserWantsSuspendOpt.get()) {
3431             if (screenOn) {
3432                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
3433             } else {
3434                 // Allow 2s for suspend optimizations to be set
3435                 mSuspendWakeLock.acquire(2000);
3436                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
3437             }
3438         }
3439         mScreenBroadcastReceived.set(true);
3440 
3441         getWifiLinkLayerStats(false);
3442         mOnTimeScreenStateChange = mOnTime;
3443         lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
3444 
3445         cancelDelayedScan();
3446 
3447         if (screenOn) {
3448             enableBackgroundScan(false);
3449             setScanAlarm(false);
3450             clearBlacklist();
3451 
3452             fullBandConnectedTimeIntervalMilli
3453                     = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
3454             // In either Disconnectedstate or ConnectedState,
3455             // start the scan alarm so as to enable autojoin
3456             if (getCurrentState() == mConnectedState
3457                     && allowFullBandScanAndAssociated()) {
3458                 if (useHalBasedAutoJoinOffload()) {
3459                     startGScanConnectedModeOffload("screenOnConnected");
3460                 } else {
3461                     // Scan after 500ms
3462                     startDelayedScan(500, null, null);
3463                 }
3464             } else if (getCurrentState() == mDisconnectedState) {
3465                 if (useHalBasedAutoJoinOffload()) {
3466                     startGScanDisconnectedModeOffload("screenOnDisconnected");
3467                 } else {
3468                     // Scan after 500ms
3469                     startDelayedScan(500, null, null);
3470                 }
3471             }
3472         } else {
3473             if (getCurrentState() == mDisconnectedState) {
3474                 // Screen Off and Disconnected and chipset doesn't support scan offload
3475                 //              => start scan alarm
3476                 // Screen Off and Disconnected and chipset does support scan offload
3477                 //              => will use scan offload (i.e. background scan)
3478                 if (useHalBasedAutoJoinOffload()) {
3479                     startGScanDisconnectedModeOffload("screenOffDisconnected");
3480                 } else {
3481                     if (!mBackgroundScanSupported) {
3482                         setScanAlarm(true);
3483                     } else {
3484                         if (!mIsScanOngoing) {
3485                             enableBackgroundScan(true);
3486                         }
3487                     }
3488                 }
3489             } else {
3490                 enableBackgroundScan(false);
3491                 if (useHalBasedAutoJoinOffload()) {
3492                     // don't try stop Gscan if it is not enabled
3493                     stopGScan("ScreenOffStop(enableBackground=" + mLegacyPnoEnabled + ") ");
3494                 }
3495             }
3496         }
3497         if (DBG) logd("backgroundScan enabled=" + mLegacyPnoEnabled);
3498 
3499         if (DBG) log("handleScreenStateChanged Exit: " + screenOn);
3500     }
3501 
checkAndSetConnectivityInstance()3502     private void checkAndSetConnectivityInstance() {
3503         if (mCm == null) {
3504             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
3505         }
3506     }
3507 
startTethering(ArrayList<String> available)3508     private boolean startTethering(ArrayList<String> available) {
3509 
3510         boolean wifiAvailable = false;
3511 
3512         checkAndSetConnectivityInstance();
3513 
3514         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
3515 
3516         for (String intf : available) {
3517             for (String regex : wifiRegexs) {
3518                 if (intf.matches(regex)) {
3519 
3520                     InterfaceConfiguration ifcg = null;
3521                     try {
3522                         ifcg = mNwService.getInterfaceConfig(intf);
3523                         if (ifcg != null) {
3524                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
3525                             ifcg.setLinkAddress(new LinkAddress(
3526                                     NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
3527                             ifcg.setInterfaceUp();
3528 
3529                             mNwService.setInterfaceConfig(intf, ifcg);
3530                         }
3531                     } catch (Exception e) {
3532                         loge("Error configuring interface " + intf + ", :" + e);
3533                         return false;
3534                     }
3535 
3536                     if (mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
3537                         loge("Error tethering on " + intf);
3538                         return false;
3539                     }
3540                     mTetherInterfaceName = intf;
3541                     return true;
3542                 }
3543             }
3544         }
3545         // We found no interfaces to tether
3546         return false;
3547     }
3548 
stopTethering()3549     private void stopTethering() {
3550 
3551         checkAndSetConnectivityInstance();
3552 
3553         /* Clear the interface config to allow dhcp correctly configure new
3554            ip settings */
3555         InterfaceConfiguration ifcg = null;
3556         try {
3557             ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
3558             if (ifcg != null) {
3559                 ifcg.setLinkAddress(
3560                         new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
3561                 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
3562             }
3563         } catch (Exception e) {
3564             loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
3565         }
3566 
3567         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
3568             loge("Untether initiate failed!");
3569         }
3570     }
3571 
isWifiTethered(ArrayList<String> active)3572     private boolean isWifiTethered(ArrayList<String> active) {
3573 
3574         checkAndSetConnectivityInstance();
3575 
3576         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
3577         for (String intf : active) {
3578             for (String regex : wifiRegexs) {
3579                 if (intf.matches(regex)) {
3580                     return true;
3581                 }
3582             }
3583         }
3584         // We found no interfaces that are tethered
3585         return false;
3586     }
3587 
3588     /**
3589      * Set the country code from the system setting value, if any.
3590      */
setCountryCode()3591     private void setCountryCode() {
3592         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
3593                 Settings.Global.WIFI_COUNTRY_CODE);
3594         if (countryCode != null && !countryCode.isEmpty()) {
3595             setCountryCode(countryCode, false);
3596         } else {
3597             //use driver default
3598         }
3599     }
3600 
3601     /**
3602      * Set the frequency band from the system setting value, if any.
3603      */
setFrequencyBand()3604     private void setFrequencyBand() {
3605         int band = Settings.Global.getInt(mContext.getContentResolver(),
3606                 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
3607 
3608         if (mWifiNative.setBand(band)) {
3609             mFrequencyBand.set(band);
3610             if (PDBG) {
3611                 logd("done set frequency band " + band);
3612             }
3613         } else {
3614             loge("Failed to set frequency band " + band);
3615         }
3616     }
3617 
3618 
3619 
setSuspendOptimizationsNative(int reason, boolean enabled)3620     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
3621         if (DBG) {
3622             log("setSuspendOptimizationsNative: " + reason + " " + enabled
3623                     + " -want " + mUserWantsSuspendOpt.get()
3624                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3625                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3626                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3627                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3628         }
3629         //mWifiNative.setSuspendOptimizations(enabled);
3630 
3631         if (enabled) {
3632             mSuspendOptNeedsDisabled &= ~reason;
3633             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
3634             if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
3635                 if (DBG) {
3636                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
3637                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3638                             + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3639                             + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3640                             + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3641                 }
3642                 mWifiNative.setSuspendOptimizations(true);
3643             }
3644         } else {
3645             mSuspendOptNeedsDisabled |= reason;
3646             mWifiNative.setSuspendOptimizations(false);
3647         }
3648     }
3649 
setSuspendOptimizations(int reason, boolean enabled)3650     private void setSuspendOptimizations(int reason, boolean enabled) {
3651         if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
3652         if (enabled) {
3653             mSuspendOptNeedsDisabled &= ~reason;
3654         } else {
3655             mSuspendOptNeedsDisabled |= reason;
3656         }
3657         if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
3658     }
3659 
setWifiState(int wifiState)3660     private void setWifiState(int wifiState) {
3661         final int previousWifiState = mWifiState.get();
3662 
3663         try {
3664             if (wifiState == WIFI_STATE_ENABLED) {
3665                 mBatteryStats.noteWifiOn();
3666             } else if (wifiState == WIFI_STATE_DISABLED) {
3667                 mBatteryStats.noteWifiOff();
3668             }
3669         } catch (RemoteException e) {
3670             loge("Failed to note battery stats in wifi");
3671         }
3672 
3673         mWifiState.set(wifiState);
3674 
3675         if (DBG) log("setWifiState: " + syncGetWifiStateByName());
3676 
3677         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
3678         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3679         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
3680         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
3681         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3682     }
3683 
setWifiApState(int wifiApState, int reason)3684     private void setWifiApState(int wifiApState, int reason) {
3685         final int previousWifiApState = mWifiApState.get();
3686 
3687         try {
3688             if (wifiApState == WIFI_AP_STATE_ENABLED) {
3689                 mBatteryStats.noteWifiOn();
3690             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
3691                 mBatteryStats.noteWifiOff();
3692             }
3693         } catch (RemoteException e) {
3694             loge("Failed to note battery stats in wifi");
3695         }
3696 
3697         // Update state
3698         mWifiApState.set(wifiApState);
3699 
3700         if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
3701 
3702         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
3703         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3704         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
3705         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
3706         if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
3707             //only set reason number when softAP start failed
3708             intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
3709         }
3710 
3711         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3712     }
3713 
3714     /*
3715     void ageOutScanResults(int age) {
3716         synchronized(mScanResultCache) {
3717             // Trim mScanResults, which prevent WifiStateMachine to return
3718             // obsolete scan results to queriers
3719             long now = System.CurrentTimeMillis();
3720             for (int i = 0; i < mScanResults.size(); i++) {
3721                 ScanResult result = mScanResults.get(i);
3722                 if ((result.seen > now || (now - result.seen) > age)) {
3723                     mScanResults.remove(i);
3724                 }
3725             }
3726         }
3727     }*/
3728 
3729     private static final String IE_STR = "ie=";
3730     private static final String ID_STR = "id=";
3731     private static final String BSSID_STR = "bssid=";
3732     private static final String FREQ_STR = "freq=";
3733     private static final String LEVEL_STR = "level=";
3734     private static final String TSF_STR = "tsf=";
3735     private static final String FLAGS_STR = "flags=";
3736     private static final String SSID_STR = "ssid=";
3737     private static final String DELIMITER_STR = "====";
3738     private static final String END_STR = "####";
3739 
3740     int emptyScanResultCount = 0;
3741 
3742     // Used for matching BSSID strings, at least one characteer must be a non-zero number
3743     private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]");
3744 
3745     /**
3746      * Format:
3747      * <p/>
3748      * id=1
3749      * bssid=68:7f:76:d7:1a:6e
3750      * freq=2412
3751      * level=-44
3752      * tsf=1344626243700342
3753      * flags=[WPA2-PSK-CCMP][WPS][ESS]
3754      * ssid=zfdy
3755      * ====
3756      * id=2
3757      * bssid=68:5f:74:d7:1a:6f
3758      * freq=5180
3759      * level=-73
3760      * tsf=1344626243700373
3761      * flags=[WPA2-PSK-CCMP][WPS][ESS]
3762      * ssid=zuby
3763      * ====
3764      */
setScanResults()3765     private void setScanResults() {
3766         mNumScanResultsKnown = 0;
3767         mNumScanResultsReturned = 0;
3768         String bssid = "";
3769         int level = 0;
3770         int freq = 0;
3771         long tsf = 0;
3772         String flags = "";
3773         WifiSsid wifiSsid = null;
3774         String scanResults;
3775         String tmpResults;
3776         StringBuffer scanResultsBuf = new StringBuffer();
3777         int sid = 0;
3778 
3779         while (true) {
3780             tmpResults = mWifiNative.scanResults(sid);
3781             if (TextUtils.isEmpty(tmpResults)) break;
3782             scanResultsBuf.append(tmpResults);
3783             scanResultsBuf.append("\n");
3784             String[] lines = tmpResults.split("\n");
3785             sid = -1;
3786             for (int i = lines.length - 1; i >= 0; i--) {
3787                 if (lines[i].startsWith(END_STR)) {
3788                     break;
3789                 } else if (lines[i].startsWith(ID_STR)) {
3790                     try {
3791                         sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
3792                     } catch (NumberFormatException e) {
3793                         // Nothing to do
3794                     }
3795                     break;
3796                 }
3797             }
3798             if (sid == -1) break;
3799         }
3800 
3801         // Age out scan results, we return all scan results found in the last 12 seconds,
3802         // and NOT all scan results since last scan.
3803         // ageOutScanResults(12000);
3804 
3805         scanResults = scanResultsBuf.toString();
3806         if (TextUtils.isEmpty(scanResults)) {
3807             emptyScanResultCount++;
3808             if (emptyScanResultCount > 10) {
3809                 // If we got too many empty scan results, the current scan cache is stale,
3810                 // hence clear it.
3811                 mScanResults = new ArrayList<>();
3812             }
3813             return;
3814         }
3815 
3816         emptyScanResultCount = 0;
3817 
3818         mWifiConfigStore.trimANQPCache(false);
3819 
3820         // note that all these splits and substrings keep references to the original
3821         // huge string buffer while the amount we really want is generally pretty small
3822         // so make copies instead (one example b/11087956 wasted 400k of heap here).
3823         synchronized (mScanResultCache) {
3824             mScanResults = new ArrayList<>();
3825             String[] lines = scanResults.split("\n");
3826             final int bssidStrLen = BSSID_STR.length();
3827             final int flagLen = FLAGS_STR.length();
3828             String infoElements = null;
3829             List<String> anqpLines = null;
3830 
3831             for (String line : lines) {
3832                 if (line.startsWith(BSSID_STR)) {
3833                     bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
3834                 } else if (line.startsWith(FREQ_STR)) {
3835                     try {
3836                         freq = Integer.parseInt(line.substring(FREQ_STR.length()));
3837                     } catch (NumberFormatException e) {
3838                         freq = 0;
3839                     }
3840                 } else if (line.startsWith(LEVEL_STR)) {
3841                     try {
3842                         level = Integer.parseInt(line.substring(LEVEL_STR.length()));
3843                         /* some implementations avoid negative values by adding 256
3844                          * so we need to adjust for that here.
3845                          */
3846                         if (level > 0) level -= 256;
3847                     } catch (NumberFormatException e) {
3848                         level = 0;
3849                     }
3850                 } else if (line.startsWith(TSF_STR)) {
3851                     try {
3852                         tsf = Long.parseLong(line.substring(TSF_STR.length()));
3853                     } catch (NumberFormatException e) {
3854                         tsf = 0;
3855                     }
3856                 } else if (line.startsWith(FLAGS_STR)) {
3857                     flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
3858                 } else if (line.startsWith(SSID_STR)) {
3859                     wifiSsid = WifiSsid.createFromAsciiEncoded(
3860                             line.substring(SSID_STR.length()));
3861                 } else if (line.startsWith(IE_STR)) {
3862                     infoElements = line;
3863                 } else if (SupplicantBridge.isAnqpAttribute(line)) {
3864                     if (anqpLines == null) {
3865                         anqpLines = new ArrayList<>();
3866                     }
3867                     anqpLines.add(line);
3868                 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
3869                     if (bssid != null) {
3870                         try {
3871                             NetworkDetail networkDetail =
3872                                     new NetworkDetail(bssid, infoElements, anqpLines, freq);
3873 
3874                             String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
3875                             if (!xssid.equals(networkDetail.getTrimmedSSID())) {
3876                                 logd(String.format(
3877                                         "Inconsistent SSID on BSSID '%s': '%s' vs '%s': %s",
3878                                         bssid, xssid, networkDetail.getSSID(), infoElements));
3879                             }
3880 
3881                             if (networkDetail.hasInterworking()) {
3882                                 Log.d(Utils.hs2LogTag(getClass()), "HSNwk: '" + networkDetail);
3883                             }
3884 
3885                             ScanDetail scanDetail = mScanResultCache.get(networkDetail);
3886                             if (scanDetail != null) {
3887                                 scanDetail.updateResults(networkDetail, level, wifiSsid, xssid,
3888                                         flags, freq, tsf);
3889                             } else {
3890                                 scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid,
3891                                         flags, level, freq, tsf);
3892                                 mScanResultCache.put(networkDetail, scanDetail);
3893                             }
3894 
3895                             mNumScanResultsReturned++; // Keep track of how many scan results we got
3896                             // as part of this scan's processing
3897                             mScanResults.add(scanDetail);
3898                         } catch (IllegalArgumentException iae) {
3899                             Log.d(TAG, "Failed to parse information elements: " + iae);
3900                         }
3901                     }
3902                     bssid = null;
3903                     level = 0;
3904                     freq = 0;
3905                     tsf = 0;
3906                     flags = "";
3907                     wifiSsid = null;
3908                     infoElements = null;
3909                     anqpLines = null;
3910                 }
3911             }
3912         }
3913 
3914         /* don't attempt autojoin if last connect attempt was just scheduled */
3915         boolean attemptAutoJoin =
3916                 (System.currentTimeMillis() - lastConnectAttemptTimestamp) > CONNECT_TIMEOUT_MSEC;
3917         SupplicantState state = mWifiInfo.getSupplicantState();
3918         String selection = mWifiConfigStore.getLastSelectedConfiguration();
3919         if (getCurrentState() == mRoamingState
3920                 || getCurrentState() == mObtainingIpState
3921                 || getCurrentState() == mScanModeState
3922                 || getCurrentState() == mDisconnectingState
3923                 || (getCurrentState() == mConnectedState
3924                 && !getEnableAutoJoinWhenAssociated())
3925                 || linkDebouncing
3926                 || state == SupplicantState.ASSOCIATING
3927                 || state == SupplicantState.AUTHENTICATING
3928                 || state == SupplicantState.FOUR_WAY_HANDSHAKE
3929                 || state == SupplicantState.GROUP_HANDSHAKE
3930                 || (/* keep autojoin enabled if user has manually selected a wifi network,
3931                         so as to make sure we reliably remain connected to this network */
3932                 mConnectionRequests == 0 && selection == null)) {
3933             // Dont attempt auto-joining again while we are already attempting to join
3934             // and/or obtaining Ip address
3935             attemptAutoJoin = false;
3936         }
3937         if (DBG) {
3938             if (selection == null) {
3939                 selection = "<none>";
3940             }
3941             logd("wifi setScanResults state" + getCurrentState()
3942                     + " sup_state=" + state
3943                     + " debouncing=" + linkDebouncing
3944                     + " mConnectionRequests=" + mConnectionRequests
3945                     + " selection=" + selection
3946                     + " mNumScanResultsReturned " + mNumScanResultsReturned
3947                      + " mScanResults " + mScanResults.size());
3948         }
3949         if (attemptAutoJoin) {
3950             messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED;
3951         }
3952         // Loose last selected configuration if we have been disconnected for 5 minutes
3953         if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) {
3954             mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
3955         }
3956 
3957         if (attemptAutoJoin) {
3958             synchronized (mScanResultCache) {
3959                 // AutoJoincontroller will directly acces the scan result list and update it with
3960                 // ScanResult status
3961                 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin);
3962             }
3963         }
3964         if (linkDebouncing) {
3965             // If debouncing, we dont re-select a SSID or BSSID hence
3966             // there is no need to call the network selection code
3967             // in WifiAutoJoinController, instead,
3968             // just try to reconnect to the same SSID by triggering a roam
3969             sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null);
3970         }
3971     }
3972 
3973     /*
3974      * Fetch RSSI, linkspeed, and frequency on current connection
3975      */
fetchRssiLinkSpeedAndFrequencyNative()3976     private void fetchRssiLinkSpeedAndFrequencyNative() {
3977         int newRssi = -1;
3978         int newLinkSpeed = -1;
3979         int newFrequency = -1;
3980 
3981         String signalPoll = mWifiNative.signalPoll();
3982 
3983         if (signalPoll != null) {
3984             String[] lines = signalPoll.split("\n");
3985             for (String line : lines) {
3986                 String[] prop = line.split("=");
3987                 if (prop.length < 2) continue;
3988                 try {
3989                     if (prop[0].equals("RSSI")) {
3990                         newRssi = Integer.parseInt(prop[1]);
3991                     } else if (prop[0].equals("LINKSPEED")) {
3992                         newLinkSpeed = Integer.parseInt(prop[1]);
3993                     } else if (prop[0].equals("FREQUENCY")) {
3994                         newFrequency = Integer.parseInt(prop[1]);
3995                     }
3996                 } catch (NumberFormatException e) {
3997                     //Ignore, defaults on rssi and linkspeed are assigned
3998                 }
3999             }
4000         }
4001 
4002         if (PDBG) {
4003             logd("fetchRssiLinkSpeedAndFrequencyNative rssi="
4004                     + Integer.toString(newRssi) + " linkspeed="
4005                     + Integer.toString(newLinkSpeed));
4006         }
4007 
4008         if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
4009             // screen out invalid values
4010             /* some implementations avoid negative values by adding 256
4011              * so we need to adjust for that here.
4012              */
4013             if (newRssi > 0) newRssi -= 256;
4014             mWifiInfo.setRssi(newRssi);
4015             /*
4016              * Rather then sending the raw RSSI out every time it
4017              * changes, we precalculate the signal level that would
4018              * be displayed in the status bar, and only send the
4019              * broadcast if that much more coarse-grained number
4020              * changes. This cuts down greatly on the number of
4021              * broadcasts, at the cost of not informing others
4022              * interested in RSSI of all the changes in signal
4023              * level.
4024              */
4025             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
4026             if (newSignalLevel != mLastSignalLevel) {
4027                 sendRssiChangeBroadcast(newRssi);
4028             }
4029             mLastSignalLevel = newSignalLevel;
4030         } else {
4031             mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
4032         }
4033 
4034         if (newLinkSpeed != -1) {
4035             mWifiInfo.setLinkSpeed(newLinkSpeed);
4036         }
4037         if (newFrequency > 0) {
4038             if (ScanResult.is5GHz(newFrequency)) {
4039                 mWifiConnectionStatistics.num5GhzConnected++;
4040             }
4041             if (ScanResult.is24GHz(newFrequency)) {
4042                 mWifiConnectionStatistics.num24GhzConnected++;
4043             }
4044             mWifiInfo.setFrequency(newFrequency);
4045         }
4046         mWifiConfigStore.updateConfiguration(mWifiInfo);
4047     }
4048 
4049     /**
4050      * Determine if we need to switch network:
4051      * - the delta determine the urgency to switch and/or or the expected evilness of the disruption
4052      * - match the uregncy of the switch versus the packet usage at the interface
4053      */
shouldSwitchNetwork(int networkDelta)4054     boolean shouldSwitchNetwork(int networkDelta) {
4055         int delta;
4056         if (networkDelta <= 0) {
4057             return false;
4058         }
4059         delta = networkDelta;
4060         if (mWifiInfo != null) {
4061             if (!getEnableAutoJoinWhenAssociated()
4062                     && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
4063                 // If AutoJoin while associated is not enabled,
4064                 // we should never switch network when already associated
4065                 delta = -1000;
4066             } else {
4067                 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present
4068                 // TODO: at the interface. We should also discriminate between ucast and mcast,
4069                 // TODO: since the rxSuccessRate include all the bonjour and Ipv6
4070                 // TODO: broadcasts
4071                 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) {
4072                     delta -= 999;
4073                 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) {
4074                     delta -= 6;
4075                 }
4076                 logd("shouldSwitchNetwork "
4077                         + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
4078                         + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
4079                         + " delta " + networkDelta + " -> " + delta);
4080             }
4081         } else {
4082             logd("shouldSwitchNetwork "
4083                     + " delta " + networkDelta + " -> " + delta);
4084         }
4085         if (delta > 0) {
4086             return true;
4087         }
4088         return false;
4089     }
4090 
4091     // Polling has completed, hence we wont have a score anymore
cleanWifiScore()4092     private void cleanWifiScore() {
4093         mWifiInfo.txBadRate = 0;
4094         mWifiInfo.txSuccessRate = 0;
4095         mWifiInfo.txRetriesRate = 0;
4096         mWifiInfo.rxSuccessRate = 0;
4097     }
4098 
4099     int mBadLinkspeedcount = 0;
4100 
4101     // For debug, provide information about the last scoring operation
4102     String wifiScoringReport = null;
4103 
calculateWifiScore(WifiLinkLayerStats stats)4104     private void calculateWifiScore(WifiLinkLayerStats stats) {
4105         StringBuilder sb = new StringBuilder();
4106 
4107         int score = 56; // Starting score, temporarily hardcoded in between 50 and 60
4108         boolean isBadLinkspeed = (mWifiInfo.is24GHz()
4109                 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24)
4110                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
4111                 < mWifiConfigStore.badLinkSpeed5);
4112         boolean isGoodLinkspeed = (mWifiInfo.is24GHz()
4113                 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24)
4114                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
4115                 >= mWifiConfigStore.goodLinkSpeed5);
4116 
4117         if (isBadLinkspeed) {
4118             if (mBadLinkspeedcount < 6)
4119                 mBadLinkspeedcount++;
4120         } else {
4121             if (mBadLinkspeedcount > 0)
4122                 mBadLinkspeedcount--;
4123         }
4124 
4125         if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")");
4126         if (isGoodLinkspeed) sb.append(" gl");
4127 
4128         /**
4129          * We want to make sure that we use the 24GHz RSSI thresholds if
4130          * there are 2.4GHz scan results
4131          * otherwise we end up lowering the score based on 5GHz values
4132          * which may cause a switch to LTE before roaming has a chance to try 2.4GHz
4133          * We also might unblacklist the configuation based on 2.4GHz
4134          * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good
4135          */
4136         boolean use24Thresholds = false;
4137         boolean homeNetworkBoost = false;
4138         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
4139         ScanDetailCache scanDetailCache =
4140                 mWifiConfigStore.getScanDetailCache(currentConfiguration);
4141         if (currentConfiguration != null && scanDetailCache != null) {
4142             currentConfiguration.setVisibility(scanDetailCache.getVisibility(12000));
4143             if (currentConfiguration.visibility != null) {
4144                 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI
4145                         && currentConfiguration.visibility.rssi24
4146                         >= (currentConfiguration.visibility.rssi5 - 2)) {
4147                     use24Thresholds = true;
4148                 }
4149             }
4150             if (scanDetailCache.size() <= 6
4151                 && currentConfiguration.allowedKeyManagement.cardinality() == 1
4152                 && currentConfiguration.allowedKeyManagement.
4153                     get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) {
4154                 // A PSK network with less than 6 known BSSIDs
4155                 // This is most likely a home network and thus we want to stick to wifi more
4156                 homeNetworkBoost = true;
4157             }
4158         }
4159         if (homeNetworkBoost) sb.append(" hn");
4160         if (use24Thresholds) sb.append(" u24");
4161 
4162         int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover
4163                 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0);
4164         sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover));
4165 
4166         boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz();
4167 
4168         boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get())
4169                 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get());
4170         boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get())
4171                 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get());
4172         boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get())
4173                 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get());
4174 
4175         if (isBadRSSI) sb.append(" br");
4176         if (isLowRSSI) sb.append(" lr");
4177         if (isHighRSSI) sb.append(" hr");
4178 
4179         int penalizedDueToUserTriggeredDisconnect = 0;        // For debug information
4180         if (currentConfiguration != null &&
4181                 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) {
4182             if (isBadRSSI) {
4183                 currentConfiguration.numTicksAtBadRSSI++;
4184                 if (currentConfiguration.numTicksAtBadRSSI > 1000) {
4185                     // We remained associated for a compound amount of time while passing
4186                     // traffic, hence loose the corresponding user triggered disabled stats
4187                     if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) {
4188                         currentConfiguration.numUserTriggeredWifiDisableBadRSSI--;
4189                     }
4190                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
4191                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
4192                     }
4193                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4194                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4195                     }
4196                     currentConfiguration.numTicksAtBadRSSI = 0;
4197                 }
4198                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
4199                         (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0
4200                                 || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
4201                                 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
4202                     score = score - 5;
4203                     penalizedDueToUserTriggeredDisconnect = 1;
4204                     sb.append(" p1");
4205                 }
4206             } else if (isLowRSSI) {
4207                 currentConfiguration.numTicksAtLowRSSI++;
4208                 if (currentConfiguration.numTicksAtLowRSSI > 1000) {
4209                     // We remained associated for a compound amount of time while passing
4210                     // traffic, hence loose the corresponding user triggered disabled stats
4211                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
4212                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
4213                     }
4214                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4215                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4216                     }
4217                     currentConfiguration.numTicksAtLowRSSI = 0;
4218                 }
4219                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
4220                         (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
4221                                 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
4222                     score = score - 5;
4223                     penalizedDueToUserTriggeredDisconnect = 2;
4224                     sb.append(" p2");
4225                 }
4226             } else if (!isHighRSSI) {
4227                 currentConfiguration.numTicksAtNotHighRSSI++;
4228                 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) {
4229                     // We remained associated for a compound amount of time while passing
4230                     // traffic, hence loose the corresponding user triggered disabled stats
4231                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4232                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4233                     }
4234                     currentConfiguration.numTicksAtNotHighRSSI = 0;
4235                 }
4236                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
4237                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4238                     score = score - 5;
4239                     penalizedDueToUserTriggeredDisconnect = 3;
4240                     sb.append(" p3");
4241                 }
4242             }
4243             sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI,
4244                     currentConfiguration.numTicksAtLowRSSI,
4245                     currentConfiguration.numTicksAtNotHighRSSI));
4246         }
4247 
4248         if (PDBG) {
4249             String rssiStatus = "";
4250             if (isBadRSSI) rssiStatus += " badRSSI ";
4251             else if (isHighRSSI) rssiStatus += " highRSSI ";
4252             else if (isLowRSSI) rssiStatus += " lowRSSI ";
4253             if (isBadLinkspeed) rssiStatus += " lowSpeed ";
4254             logd("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency())
4255                     + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed())
4256                     + " score=" + Integer.toString(mWifiInfo.score)
4257                     + rssiStatus
4258                     + " -> txbadrate=" + String.format("%.2f", mWifiInfo.txBadRate)
4259                     + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
4260                     + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate)
4261                     + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
4262                     + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect);
4263         }
4264 
4265         if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3)
4266                 && (isBadRSSI || isLowRSSI)) {
4267             // Link is stuck
4268             if (mWifiInfo.linkStuckCount < 5)
4269                 mWifiInfo.linkStuckCount += 1;
4270             sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount));
4271             if (PDBG) logd(" bad link -> stuck count ="
4272                     + Integer.toString(mWifiInfo.linkStuckCount));
4273         } else if (mWifiInfo.txBadRate < 0.3) {
4274             if (mWifiInfo.linkStuckCount > 0)
4275                 mWifiInfo.linkStuckCount -= 1;
4276             sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount));
4277             if (PDBG) logd(" good link -> stuck count ="
4278                     + Integer.toString(mWifiInfo.linkStuckCount));
4279         }
4280 
4281         sb.append(String.format(" [%d", score));
4282 
4283         if (mWifiInfo.linkStuckCount > 1) {
4284             // Once link gets stuck for more than 3 seconds, start reducing the score
4285             score = score - 2 * (mWifiInfo.linkStuckCount - 1);
4286         }
4287         sb.append(String.format(",%d", score));
4288 
4289         if (isBadLinkspeed) {
4290             score -= 4;
4291             if (PDBG) {
4292                 logd(" isBadLinkspeed   ---> count=" + mBadLinkspeedcount
4293                         + " score=" + Integer.toString(score));
4294             }
4295         } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {
4296             score += 4; // So as bad rssi alone dont kill us
4297         }
4298         sb.append(String.format(",%d", score));
4299 
4300         if (isBadRSSI) {
4301             if (mWifiInfo.badRssiCount < 7)
4302                 mWifiInfo.badRssiCount += 1;
4303         } else if (isLowRSSI) {
4304             mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1
4305             if (mWifiInfo.badRssiCount > 0) {
4306                 // Decrement bad Rssi count
4307                 mWifiInfo.badRssiCount -= 1;
4308             }
4309         } else {
4310             mWifiInfo.badRssiCount = 0;
4311             mWifiInfo.lowRssiCount = 0;
4312         }
4313 
4314         score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount;
4315         sb.append(String.format(",%d", score));
4316 
4317         if (PDBG) logd(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount)
4318                 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount)
4319                 + " --> score " + Integer.toString(score));
4320 
4321 
4322         if (isHighRSSI) {
4323             score += 5;
4324             if (PDBG) logd(" isHighRSSI       ---> score=" + Integer.toString(score));
4325         }
4326         sb.append(String.format(",%d]", score));
4327 
4328         sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount));
4329 
4330         //sanitize boundaries
4331         if (score > NetworkAgent.WIFI_BASE_SCORE)
4332             score = NetworkAgent.WIFI_BASE_SCORE;
4333         if (score < 0)
4334             score = 0;
4335 
4336         //report score
4337         if (score != mWifiInfo.score) {
4338             if (DBG) {
4339                 logd("calculateWifiScore() report new score " + Integer.toString(score));
4340             }
4341             mWifiInfo.score = score;
4342             if (mNetworkAgent != null) {
4343                 mNetworkAgent.sendNetworkScore(score);
4344             }
4345         }
4346         wifiScoringReport = sb.toString();
4347     }
4348 
getTxPacketRate()4349     public double getTxPacketRate() {
4350         if (mWifiInfo != null) {
4351             return mWifiInfo.txSuccessRate;
4352         }
4353         return -1;
4354     }
4355 
getRxPacketRate()4356     public double getRxPacketRate() {
4357         if (mWifiInfo != null) {
4358             return mWifiInfo.rxSuccessRate;
4359         }
4360         return -1;
4361     }
4362 
4363     /**
4364      * Fetch TX packet counters on current connection
4365      */
fetchPktcntNative(RssiPacketCountInfo info)4366     private void fetchPktcntNative(RssiPacketCountInfo info) {
4367         String pktcntPoll = mWifiNative.pktcntPoll();
4368 
4369         if (pktcntPoll != null) {
4370             String[] lines = pktcntPoll.split("\n");
4371             for (String line : lines) {
4372                 String[] prop = line.split("=");
4373                 if (prop.length < 2) continue;
4374                 try {
4375                     if (prop[0].equals("TXGOOD")) {
4376                         info.txgood = Integer.parseInt(prop[1]);
4377                     } else if (prop[0].equals("TXBAD")) {
4378                         info.txbad = Integer.parseInt(prop[1]);
4379                     }
4380                 } catch (NumberFormatException e) {
4381                     // Ignore
4382                 }
4383             }
4384         }
4385     }
4386 
clearIPv4Address(String iface)4387     private boolean clearIPv4Address(String iface) {
4388         try {
4389             InterfaceConfiguration ifcg = new InterfaceConfiguration();
4390             ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
4391             mNwService.setInterfaceConfig(iface, ifcg);
4392             return true;
4393         } catch (RemoteException e) {
4394             return false;
4395         }
4396     }
4397 
isProvisioned(LinkProperties lp)4398     private boolean isProvisioned(LinkProperties lp) {
4399         return lp.isProvisioned() ||
4400                 (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address());
4401     }
4402 
4403     /**
4404      * Creates a new LinkProperties object by merging information from various sources.
4405      * <p/>
4406      * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
4407      * netlink, static configuration, ...). When one of these sources of information has updated
4408      * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
4409      * information that came from other sources. Instead, when one of those sources has new
4410      * information, we update the object that tracks the information from that source and then
4411      * call this method to integrate the change into a new LinkProperties object for subsequent
4412      * comparison with mLinkProperties.
4413      * <p/>
4414      * The information used to build LinkProperties is currently obtained as follows:
4415      *     - Interface name: set in the constructor.
4416      *     - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker.
4417      *     - IPv4 routes, DNS servers, and domains: DHCP.
4418      *     - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker.
4419      *     - HTTP proxy: the wifi config store.
4420      */
makeLinkProperties()4421     private LinkProperties makeLinkProperties() {
4422         LinkProperties newLp = new LinkProperties();
4423 
4424         // Interface name, proxy, and TCP buffer sizes are locally configured.
4425         newLp.setInterfaceName(mInterfaceName);
4426         newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
4427         if (!TextUtils.isEmpty(mTcpBufferSizes)) {
4428             newLp.setTcpBufferSizes(mTcpBufferSizes);
4429         }
4430 
4431         // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink.
4432         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
4433         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
4434         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
4435             newLp.addRoute(route);
4436         }
4437         for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
4438             // Only add likely reachable DNS servers.
4439             // TODO: investigate deleting this.
4440             if (newLp.isReachable(dns)) {
4441                 newLp.addDnsServer(dns);
4442             }
4443         }
4444 
4445         // IPv4 routes, DNS servers and domains come from mDhcpResults.
4446         synchronized (mDhcpResultsLock) {
4447             // Even when we're using static configuration, we don't need to look at the config
4448             // store, because static IP configuration also populates mDhcpResults.
4449             if ((mDhcpResults != null)) {
4450                 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
4451                     newLp.addRoute(route);
4452                 }
4453                 for (InetAddress dns : mDhcpResults.dnsServers) {
4454                     // Only add likely reachable DNS servers.
4455                     // TODO: investigate deleting this.
4456                     if (newLp.isReachable(dns)) {
4457                         newLp.addDnsServer(dns);
4458                     }
4459                 }
4460                 newLp.setDomains(mDhcpResults.domains);
4461             }
4462         }
4463 
4464         return newLp;
4465     }
4466 
updateLinkProperties(int reason)4467     private void updateLinkProperties(int reason) {
4468         LinkProperties newLp = makeLinkProperties();
4469 
4470         final boolean linkChanged = !newLp.equals(mLinkProperties);
4471         final boolean wasProvisioned = isProvisioned(mLinkProperties);
4472         final boolean isProvisioned = isProvisioned(newLp);
4473         // TODO: Teach LinkProperties how to understand static assignment
4474         // and simplify all this provisioning change detection logic by
4475         // unifying it under LinkProperties.compareProvisioning().
4476         final boolean lostProvisioning =
4477                 (wasProvisioned && !isProvisioned) ||
4478                 (mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address()) ||
4479                 (mLinkProperties.isIPv6Provisioned() && !newLp.isIPv6Provisioned());
4480         final DetailedState detailedState = getNetworkDetailedState();
4481 
4482         if (linkChanged) {
4483             if (DBG) {
4484                 log("Link configuration changed for netId: " + mLastNetworkId
4485                         + " old: " + mLinkProperties + " new: " + newLp);
4486             }
4487             mLinkProperties = newLp;
4488             if (mIpReachabilityMonitor != null) {
4489                 mIpReachabilityMonitor.updateLinkProperties(mLinkProperties);
4490             }
4491             if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
4492         }
4493 
4494         if (lostProvisioning) {
4495             log("Lost IP layer provisioning!" +
4496                     " was: " + mLinkProperties +
4497                     " now: " + newLp);
4498         }
4499 
4500         if (DBG) {
4501             StringBuilder sb = new StringBuilder();
4502             sb.append("updateLinkProperties nid: " + mLastNetworkId);
4503             sb.append(" state: " + detailedState);
4504             sb.append(" reason: " + smToString(reason));
4505 
4506             if (mLinkProperties != null) {
4507                 if (mLinkProperties.hasIPv4Address()) {
4508                     sb.append(" v4");
4509                 }
4510                 if (mLinkProperties.hasGlobalIPv6Address()) {
4511                     sb.append(" v6");
4512                 }
4513                 if (mLinkProperties.hasIPv4DefaultRoute()) {
4514                     sb.append(" v4r");
4515                 }
4516                 if (mLinkProperties.hasIPv6DefaultRoute()) {
4517                     sb.append(" v6r");
4518                 }
4519                 if (mLinkProperties.hasIPv4DnsServer()) {
4520                     sb.append(" v4dns");
4521                 }
4522                 if (mLinkProperties.hasIPv6DnsServer()) {
4523                     sb.append(" v6dns");
4524                 }
4525                 if (isProvisioned) {
4526                     sb.append(" isprov");
4527                 }
4528             }
4529             logd(sb.toString());
4530         }
4531 
4532         // If we just configured or lost IP configuration, do the needful.
4533         // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost()
4534         // here because those should only be called if we're attempting to connect or already
4535         // connected, whereas updateLinkProperties can be called at any time.
4536         switch (reason) {
4537             case DhcpStateMachine.DHCP_SUCCESS:
4538             case CMD_STATIC_IP_SUCCESS:
4539                 // IPv4 provisioning succeded. Advance to connected state.
4540                 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
4541                 if (!isProvisioned) {
4542                     // Can never happen unless DHCP reports success but isProvisioned thinks the
4543                     // resulting configuration is invalid (e.g., no IPv4 address, or the state in
4544                     // mLinkProperties is out of sync with reality, or there's a bug in this code).
4545                     // TODO: disconnect here instead. If our configuration is not usable, there's no
4546                     // point in staying connected, and if mLinkProperties is out of sync with
4547                     // reality, that will cause problems in the future.
4548                     logd("IPv4 config succeeded, but not provisioned");
4549                 }
4550                 break;
4551 
4552             case DhcpStateMachine.DHCP_FAILURE:
4553                 // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it,
4554                 // give up and disconnect.
4555                 // If we're already provisioned (e.g., IPv6-only network), stay connected.
4556                 if (!isProvisioned || lostProvisioning) {
4557                     sendMessage(CMD_IP_CONFIGURATION_LOST);
4558                 } else {
4559                     // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network).
4560                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
4561 
4562                     // To be sure we don't get stuck with a non-working network if all we had is
4563                     // IPv4, remove the IPv4 address from the interface (since we're using DHCP,
4564                     // and DHCP failed). If we had an IPv4 address before, the deletion of the
4565                     // address  will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was
4566                     // necessary for provisioning, its deletion will cause us to disconnect.
4567                     //
4568                     // This shouldn't be needed, because on an IPv4-only network a DHCP failure will
4569                     // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will
4570                     // not return true if we're using DHCP and don't have an IPv4 default route. So
4571                     // for now it's only here for extra redundancy. However, it will increase
4572                     // robustness if we move to getting IPv4 routes from netlink as well.
4573                     loge("DHCP failure: provisioned, clearing IPv4 address.");
4574                     if (!clearIPv4Address(mInterfaceName)) {
4575                         sendMessage(CMD_IP_CONFIGURATION_LOST);
4576                     }
4577                 }
4578                 break;
4579 
4580             case CMD_STATIC_IP_FAILURE:
4581                 // Static configuration was invalid, or an error occurred in applying it. Give up.
4582                 sendMessage(CMD_IP_CONFIGURATION_LOST);
4583                 break;
4584 
4585             case CMD_UPDATE_LINKPROPERTIES:
4586                 // IP addresses, DNS servers, etc. changed. Act accordingly.
4587                 if (lostProvisioning) {
4588                     // We no longer have a usable network configuration. Disconnect.
4589                     sendMessage(CMD_IP_CONFIGURATION_LOST);
4590                 } else if (!wasProvisioned && isProvisioned) {
4591                     // We have a usable IPv6-only config. Advance to connected state.
4592                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
4593                 }
4594                 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) {
4595                     // If anything has changed and we're already connected, send out a notification.
4596                     sendLinkConfigurationChangedBroadcast();
4597                 }
4598                 break;
4599         }
4600     }
4601 
4602     /**
4603      * Clears all our link properties.
4604      */
clearLinkProperties()4605     private void clearLinkProperties() {
4606         // Clear the link properties obtained from DHCP and netlink.
4607         synchronized (mDhcpResultsLock) {
4608             if (mDhcpResults != null) {
4609                 mDhcpResults.clear();
4610             }
4611         }
4612         mNetlinkTracker.clearLinkProperties();
4613         if (mIpReachabilityMonitor != null) {
4614             mIpReachabilityMonitor.clearLinkProperties();
4615         }
4616 
4617         // Now clear the merged link properties.
4618         mLinkProperties.clear();
4619         if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
4620     }
4621 
4622     /**
4623      * try to update default route MAC address.
4624      */
updateDefaultRouteMacAddress(int timeout)4625     private String updateDefaultRouteMacAddress(int timeout) {
4626         String address = null;
4627         for (RouteInfo route : mLinkProperties.getRoutes()) {
4628             if (route.isDefaultRoute() && route.hasGateway()) {
4629                 InetAddress gateway = route.getGateway();
4630                 if (gateway instanceof Inet4Address) {
4631                     if (PDBG) {
4632                         logd("updateDefaultRouteMacAddress found Ipv4 default :"
4633                                 + gateway.getHostAddress());
4634                     }
4635                     address = macAddressFromRoute(gateway.getHostAddress());
4636                     /* The gateway's MAC address is known */
4637                     if ((address == null) && (timeout > 0)) {
4638                         boolean reachable = false;
4639                         try {
4640                             reachable = gateway.isReachable(timeout);
4641                         } catch (Exception e) {
4642                             loge("updateDefaultRouteMacAddress exception reaching :"
4643                                     + gateway.getHostAddress());
4644 
4645                         } finally {
4646                             if (reachable == true) {
4647 
4648                                 address = macAddressFromRoute(gateway.getHostAddress());
4649                                 if (PDBG) {
4650                                     logd("updateDefaultRouteMacAddress reachable (tried again) :"
4651                                             + gateway.getHostAddress() + " found " + address);
4652                                 }
4653                             }
4654                         }
4655                     }
4656                     if (address != null) {
4657                         mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address);
4658                     }
4659                 }
4660             }
4661         }
4662         return address;
4663     }
4664 
sendScanResultsAvailableBroadcast(boolean scanSucceeded)4665     void sendScanResultsAvailableBroadcast(boolean scanSucceeded) {
4666         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
4667         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4668         intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded);
4669         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4670     }
4671 
sendRssiChangeBroadcast(final int newRssi)4672     private void sendRssiChangeBroadcast(final int newRssi) {
4673         try {
4674             mBatteryStats.noteWifiRssiChanged(newRssi);
4675         } catch (RemoteException e) {
4676             // Won't happen.
4677         }
4678         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
4679         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4680         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
4681         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4682     }
4683 
sendNetworkStateChangeBroadcast(String bssid)4684     private void sendNetworkStateChangeBroadcast(String bssid) {
4685         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
4686         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4687         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
4688         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
4689         if (bssid != null)
4690             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
4691         if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
4692                 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
4693             // We no longer report MAC address to third-parties and our code does
4694             // not rely on this broadcast, so just send the default MAC address.
4695             WifiInfo sentWifiInfo = new WifiInfo(mWifiInfo);
4696             sentWifiInfo.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
4697             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, sentWifiInfo);
4698         }
4699         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4700     }
4701 
getWiFiInfoForUid(int uid)4702     private WifiInfo getWiFiInfoForUid(int uid) {
4703         if (Binder.getCallingUid() == Process.myUid()) {
4704             return mWifiInfo;
4705         }
4706 
4707         WifiInfo result = new WifiInfo(mWifiInfo);
4708         result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
4709 
4710         IBinder binder = ServiceManager.getService("package");
4711         IPackageManager packageManager = IPackageManager.Stub.asInterface(binder);
4712 
4713         try {
4714             if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
4715                     uid) == PackageManager.PERMISSION_GRANTED) {
4716                 result.setMacAddress(mWifiInfo.getMacAddress());
4717             }
4718         } catch (RemoteException e) {
4719             Log.e(TAG, "Error checking receiver permission", e);
4720         }
4721 
4722         return result;
4723     }
4724 
sendLinkConfigurationChangedBroadcast()4725     private void sendLinkConfigurationChangedBroadcast() {
4726         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
4727         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4728         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
4729         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4730     }
4731 
sendSupplicantConnectionChangedBroadcast(boolean connected)4732     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
4733         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
4734         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4735         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
4736         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4737     }
4738 
4739     /**
4740      * Record the detailed state of a network.
4741      *
4742      * @param state the new {@code DetailedState}
4743      */
setNetworkDetailedState(NetworkInfo.DetailedState state)4744     private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
4745         boolean hidden = false;
4746 
4747         if (linkDebouncing || isRoaming()) {
4748             // There is generally a confusion in the system about colluding
4749             // WiFi Layer 2 state (as reported by supplicant) and the Network state
4750             // which leads to multiple confusion.
4751             //
4752             // If link is de-bouncing or roaming, we already have an IP address
4753             // as well we were connected and are doing L2 cycles of
4754             // reconnecting or renewing IP address to check that we still have it
4755             // This L2 link flapping should ne be reflected into the Network state
4756             // which is the state of the WiFi Network visible to Layer 3 and applications
4757             // Note that once debouncing and roaming are completed, we will
4758             // set the Network state to where it should be, or leave it as unchanged
4759             //
4760             hidden = true;
4761         }
4762         if (DBG) {
4763             log("setDetailed state, old ="
4764                     + mNetworkInfo.getDetailedState() + " and new state=" + state
4765                     + " hidden=" + hidden);
4766         }
4767         if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) {
4768             // Always indicate that SSID has changed
4769             if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
4770                 if (DBG) {
4771                     log("setDetailed state send new extra info" + mWifiInfo.getSSID());
4772                 }
4773                 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
4774                 sendNetworkStateChangeBroadcast(null);
4775             }
4776         }
4777         if (hidden == true) {
4778             return false;
4779         }
4780 
4781         if (state != mNetworkInfo.getDetailedState()) {
4782             mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
4783             if (mNetworkAgent != null) {
4784                 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4785             }
4786             sendNetworkStateChangeBroadcast(null);
4787             return true;
4788         }
4789         return false;
4790     }
4791 
getNetworkDetailedState()4792     private DetailedState getNetworkDetailedState() {
4793         return mNetworkInfo.getDetailedState();
4794     }
4795 
handleSupplicantStateChange(Message message)4796     private SupplicantState handleSupplicantStateChange(Message message) {
4797         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
4798         SupplicantState state = stateChangeResult.state;
4799         // Supplicant state change
4800         // [31-13] Reserved for future use
4801         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
4802         // 50023 supplicant_state_changed (custom|1|5)
4803         mWifiInfo.setSupplicantState(state);
4804         // Network id is only valid when we start connecting
4805         if (SupplicantState.isConnecting(state)) {
4806             mWifiInfo.setNetworkId(stateChangeResult.networkId);
4807         } else {
4808             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
4809         }
4810 
4811         mWifiInfo.setBSSID(stateChangeResult.BSSID);
4812 
4813         if (mWhiteListedSsids != null
4814                 && mWhiteListedSsids.length > 0
4815                 && stateChangeResult.wifiSsid != null) {
4816             String SSID = stateChangeResult.wifiSsid.toString();
4817             String currentSSID = mWifiInfo.getSSID();
4818             if (SSID != null
4819                     && currentSSID != null
4820                     && !SSID.equals(WifiSsid.NONE)) {
4821                     // Remove quote before comparing
4822                     if (SSID.length() >= 2 && SSID.charAt(0) == '"'
4823                             && SSID.charAt(SSID.length() - 1) == '"')
4824                     {
4825                         SSID = SSID.substring(1, SSID.length() - 1);
4826                     }
4827                     if (currentSSID.length() >= 2 && currentSSID.charAt(0) == '"'
4828                             && currentSSID.charAt(currentSSID.length() - 1) == '"') {
4829                         currentSSID = currentSSID.substring(1, currentSSID.length() - 1);
4830                     }
4831                     if ((!SSID.equals(currentSSID)) && (getCurrentState() == mConnectedState)) {
4832                         lastConnectAttemptTimestamp = System.currentTimeMillis();
4833                         targetWificonfiguration
4834                             = mWifiConfigStore.getWifiConfiguration(mWifiInfo.getNetworkId());
4835                         transitionTo(mRoamingState);
4836                     }
4837              }
4838         }
4839 
4840         mWifiInfo.setSSID(stateChangeResult.wifiSsid);
4841         mWifiInfo.setEphemeral(mWifiConfigStore.isEphemeral(mWifiInfo.getNetworkId()));
4842 
4843         mSupplicantStateTracker.sendMessage(Message.obtain(message));
4844 
4845         return state;
4846     }
4847 
4848     /**
4849      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
4850      * using the interface, stopping DHCP & disabling interface
4851      */
handleNetworkDisconnect()4852     private void handleNetworkDisconnect() {
4853         if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
4854                 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
4855                 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
4856                 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
4857                 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
4858 
4859 
4860         clearCurrentConfigBSSID("handleNetworkDisconnect");
4861 
4862         stopDhcp();
4863 
4864         try {
4865             mNwService.clearInterfaceAddresses(mInterfaceName);
4866             mNwService.disableIpv6(mInterfaceName);
4867         } catch (Exception e) {
4868             loge("Failed to clear addresses or disable ipv6" + e);
4869         }
4870 
4871         /* Reset data structures */
4872         mBadLinkspeedcount = 0;
4873         mWifiInfo.reset();
4874         linkDebouncing = false;
4875         /* Reset roaming parameters */
4876         mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
4877 
4878         /**
4879          *  fullBandConnectedTimeIntervalMilli:
4880          *  - start scans at mWifiConfigStore.wifiAssociatedShortScanIntervalMilli seconds interval
4881          *  - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli
4882          *  Initialize to sane value = 20 seconds
4883          */
4884         fullBandConnectedTimeIntervalMilli = 20 * 1000;
4885 
4886         setNetworkDetailedState(DetailedState.DISCONNECTED);
4887         if (mNetworkAgent != null) {
4888             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4889             mNetworkAgent = null;
4890         }
4891         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
4892 
4893         /* Clear network properties */
4894         clearLinkProperties();
4895 
4896         /* Cend event to CM & network change broadcast */
4897         sendNetworkStateChangeBroadcast(mLastBssid);
4898 
4899         /* Cancel auto roam requests */
4900         autoRoamSetBSSID(mLastNetworkId, "any");
4901 
4902         mLastBssid = null;
4903         registerDisconnected();
4904         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4905     }
4906 
handleSupplicantConnectionLoss(boolean killSupplicant)4907     private void handleSupplicantConnectionLoss(boolean killSupplicant) {
4908         /* Socket connection can be lost when we do a graceful shutdown
4909         * or when the driver is hung. Ensure supplicant is stopped here.
4910         */
4911         if (killSupplicant) {
4912             mWifiMonitor.killSupplicant(mP2pSupported);
4913         }
4914         mWifiNative.closeSupplicantConnection();
4915         sendSupplicantConnectionChangedBroadcast(false);
4916         setWifiState(WIFI_STATE_DISABLED);
4917     }
4918 
handlePreDhcpSetup()4919     void handlePreDhcpSetup() {
4920         mDhcpActive = true;
4921         if (!mBluetoothConnectionActive) {
4922             /*
4923              * There are problems setting the Wi-Fi driver's power
4924              * mode to active when bluetooth coexistence mode is
4925              * enabled or sense.
4926              * <p>
4927              * We set Wi-Fi to active mode when
4928              * obtaining an IP address because we've found
4929              * compatibility issues with some routers with low power
4930              * mode.
4931              * <p>
4932              * In order for this active power mode to properly be set,
4933              * we disable coexistence mode until we're done with
4934              * obtaining an IP address.  One exception is if we
4935              * are currently connected to a headset, since disabling
4936              * coexistence would interrupt that connection.
4937              */
4938             // Disable the coexistence mode
4939             mWifiNative.setBluetoothCoexistenceMode(
4940                     mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
4941         }
4942 
4943         // Disable power save and suspend optimizations during DHCP
4944         // Note: The order here is important for now. Brcm driver changes
4945         // power settings when we control suspend mode optimizations.
4946         // TODO: Remove this comment when the driver is fixed.
4947         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
4948         mWifiNative.setPowerSave(false);
4949 
4950         // Update link layer stats
4951         getWifiLinkLayerStats(false);
4952 
4953         /* P2p discovery breaks dhcp, shut it down in order to get through this */
4954         Message msg = new Message();
4955         msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
4956         msg.arg1 = WifiP2pServiceImpl.ENABLED;
4957         msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;
4958         msg.obj = mDhcpStateMachine;
4959         mWifiP2pChannel.sendMessage(msg);
4960     }
4961 
4962 
useLegacyDhcpClient()4963     private boolean useLegacyDhcpClient() {
4964         return Settings.Global.getInt(
4965                 mContext.getContentResolver(),
4966                 Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1;
4967     }
4968 
maybeInitDhcpStateMachine()4969     private void maybeInitDhcpStateMachine() {
4970         if (mDhcpStateMachine == null) {
4971             if (useLegacyDhcpClient()) {
4972                 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
4973                         mContext, WifiStateMachine.this, mInterfaceName);
4974             } else {
4975                 mDhcpStateMachine = DhcpClient.makeDhcpStateMachine(
4976                         mContext, WifiStateMachine.this, mInterfaceName);
4977             }
4978         }
4979     }
4980 
startDhcp()4981     void startDhcp() {
4982         maybeInitDhcpStateMachine();
4983         mDhcpStateMachine.registerForPreDhcpNotification();
4984         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
4985     }
4986 
renewDhcp()4987     void renewDhcp() {
4988         maybeInitDhcpStateMachine();
4989         mDhcpStateMachine.registerForPreDhcpNotification();
4990         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP);
4991     }
4992 
stopDhcp()4993     void stopDhcp() {
4994         if (mDhcpStateMachine != null) {
4995             /* In case we were in middle of DHCP operation restore back powermode */
4996             handlePostDhcpSetup();
4997             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
4998         }
4999     }
5000 
handlePostDhcpSetup()5001     void handlePostDhcpSetup() {
5002         /* Restore power save and suspend optimizations */
5003         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
5004         mWifiNative.setPowerSave(true);
5005 
5006         mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
5007 
5008         // Set the coexistence mode back to its default value
5009         mWifiNative.setBluetoothCoexistenceMode(
5010                 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
5011 
5012         mDhcpActive = false;
5013     }
5014 
connectScanningService()5015     void connectScanningService() {
5016 
5017         if (mWifiScanner == null) {
5018             mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
5019         }
5020     }
5021 
handleIPv4Success(DhcpResults dhcpResults, int reason)5022     private void handleIPv4Success(DhcpResults dhcpResults, int reason) {
5023 
5024         if (PDBG) {
5025             logd("handleIPv4Success <" + dhcpResults.toString() + ">");
5026             logd("link address " + dhcpResults.ipAddress);
5027         }
5028 
5029         Inet4Address addr;
5030         synchronized (mDhcpResultsLock) {
5031             mDhcpResults = dhcpResults;
5032             addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
5033         }
5034 
5035         if (isRoaming()) {
5036             int previousAddress = mWifiInfo.getIpAddress();
5037             int newAddress = NetworkUtils.inetAddressToInt(addr);
5038             if (previousAddress != newAddress) {
5039                 logd("handleIPv4Success, roaming and address changed" +
5040                         mWifiInfo + " got: " + addr);
5041             }
5042         }
5043         mWifiInfo.setInetAddress(addr);
5044         mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
5045         updateLinkProperties(reason);
5046     }
5047 
handleSuccessfulIpConfiguration()5048     private void handleSuccessfulIpConfiguration() {
5049         mLastSignalLevel = -1; // Force update of signal strength
5050         WifiConfiguration c = getCurrentWifiConfiguration();
5051         if (c != null) {
5052             // Reset IP failure tracking
5053             c.numConnectionFailures = 0;
5054 
5055             // Tell the framework whether the newly connected network is trusted or untrusted.
5056             updateCapabilities(c);
5057         }
5058         if (c != null) {
5059             ScanResult result = getCurrentScanResult();
5060             if (result == null) {
5061                 logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
5062                         c.configKey());
5063             } else {
5064                 // Clear the per BSSID failure count
5065                 result.numIpConfigFailures = 0;
5066                 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry
5067                 // any BSSID, even though it may already have a non zero ip failure count,
5068                 // this will typically happen if the user walks away and come back to his arrea
5069                 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted
5070                 // in supplicant for a couple of hours or a day
5071                 mWifiConfigStore.clearBssidBlacklist();
5072             }
5073         }
5074     }
5075 
handleIPv4Failure(int reason)5076     private void handleIPv4Failure(int reason) {
5077         synchronized(mDhcpResultsLock) {
5078              if (mDhcpResults != null) {
5079                  mDhcpResults.clear();
5080              }
5081         }
5082         if (PDBG) {
5083             logd("handleIPv4Failure");
5084         }
5085         updateLinkProperties(reason);
5086     }
5087 
handleIpConfigurationLost()5088     private void handleIpConfigurationLost() {
5089         mWifiInfo.setInetAddress(null);
5090         mWifiInfo.setMeteredHint(false);
5091 
5092         mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false,
5093                 "DHCP FAILURE", mWifiInfo.getBSSID());
5094 
5095         /* DHCP times out after about 30 seconds, we do a
5096          * disconnect thru supplicant, we will let autojoin retry connecting to the network
5097          */
5098         mWifiNative.disconnect();
5099     }
5100 
5101     // TODO: De-duplicated this and handleIpConfigurationLost().
handleIpReachabilityLost()5102     private void handleIpReachabilityLost() {
5103         // No need to be told about any additional neighbors that might also
5104         // become unreachable--quiet them now while we start disconnecting.
5105         if (mIpReachabilityMonitor != null) {
5106             mIpReachabilityMonitor.clearLinkProperties();
5107         }
5108 
5109         mWifiInfo.setInetAddress(null);
5110         mWifiInfo.setMeteredHint(false);
5111 
5112         // TODO: Determine whether to call some form of mWifiConfigStore.handleSSIDStateChange().
5113 
5114         // Disconnect via supplicant, and let autojoin retry connecting to the network.
5115         mWifiNative.disconnect();
5116     }
5117 
convertFrequencyToChannelNumber(int frequency)5118     private int convertFrequencyToChannelNumber(int frequency) {
5119         if (frequency >= 2412 && frequency <= 2484) {
5120             return (frequency -2412) / 5 + 1;
5121         } else if (frequency >= 5170  &&  frequency <=5825) {
5122             //DFS is included
5123             return (frequency -5170) / 5 + 34;
5124         } else {
5125             return 0;
5126         }
5127     }
5128 
chooseApChannel(int apBand)5129     private int chooseApChannel(int apBand) {
5130         int apChannel;
5131         int[] channel;
5132 
5133         if (apBand == 0)  {
5134             if (mWifiApConfigStore.allowed2GChannel == null ||
5135                     mWifiApConfigStore.allowed2GChannel.size() == 0) {
5136                 //most safe channel to use
5137                 if(DBG) {
5138                     Log.d(TAG, "No specified 2G allowed channel list");
5139                 }
5140                 apChannel = 6;
5141             } else {
5142                 int index = mRandom.nextInt(mWifiApConfigStore.allowed2GChannel.size());
5143                 apChannel = mWifiApConfigStore.allowed2GChannel.get(index).intValue();
5144             }
5145         } else {
5146             //5G without DFS
5147             channel = mWifiNative.getChannelsForBand(2);
5148             if (channel != null && channel.length > 0) {
5149                 apChannel = channel[mRandom.nextInt(channel.length)];
5150                 apChannel = convertFrequencyToChannelNumber(apChannel);
5151             } else {
5152                 Log.e(TAG, "SoftAp do not get available channel list");
5153                 apChannel = 0;
5154             }
5155         }
5156 
5157         if(DBG) {
5158             Log.d(TAG, "SoftAp set on channel " + apChannel);
5159         }
5160 
5161         return apChannel;
5162     }
5163 
5164     /* SoftAP configuration */
enableSoftAp()5165     private boolean enableSoftAp() {
5166         if (WifiNative.getInterfaces() != 0) {
5167             if (!mWifiNative.toggleInterface(0)) {
5168                 if (DBG) Log.e(TAG, "toggleInterface failed");
5169                 return false;
5170             }
5171         } else {
5172             if (DBG) Log.d(TAG, "No interfaces to toggle");
5173         }
5174 
5175         try {
5176             mNwService.wifiFirmwareReload(mInterfaceName, "AP");
5177             if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
5178         } catch (Exception e) {
5179             Log.e(TAG, "Failed to reload AP firmware " + e);
5180         }
5181 
5182         if (WifiNative.startHal() == false) {
5183             /* starting HAL is optional */
5184             Log.e(TAG, "Failed to start HAL");
5185         }
5186         return true;
5187     }
5188 
5189     /* Current design is to not set the config on a running hostapd but instead
5190      * stop and start tethering when user changes config on a running access point
5191      *
5192      * TODO: Add control channel setup through hostapd that allows changing config
5193      * on a running daemon
5194      */
startSoftApWithConfig(final WifiConfiguration configuration)5195     private void startSoftApWithConfig(final WifiConfiguration configuration) {
5196         // set channel
5197         final WifiConfiguration config = new WifiConfiguration(configuration);
5198 
5199         if (DBG) {
5200             Log.d(TAG, "SoftAp config channel is: " + config.apChannel);
5201         }
5202 
5203         //We need HAL support to set country code and get available channel list, if HAL is
5204         //not available, like razor, we regress to original implementaion (2GHz, channel 6)
5205         if (mWifiNative.isHalStarted()) {
5206             //set country code through HAL Here
5207             if (mSetCountryCode != null) {
5208                 if (!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) {
5209                     if (config.apBand != 0) {
5210                         Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz");
5211                         //countrycode is mandatory for 5GHz
5212                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
5213                         return;
5214                     }
5215                 }
5216             } else {
5217                 if (config.apBand != 0) {
5218                     //countrycode is mandatory for 5GHz
5219                     Log.e(TAG, "Can not setup softAp on 5GHz without country code!");
5220                     sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
5221                     return;
5222                 }
5223             }
5224 
5225             if (config.apChannel == 0) {
5226                 config.apChannel = chooseApChannel(config.apBand);
5227                 if (config.apChannel == 0) {
5228                     if(mWifiNative.isGetChannelsForBandSupported()) {
5229                         //fail to get available channel
5230                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_NO_CHANNEL);
5231                         return;
5232                     } else {
5233                         //for some old device, wifiHal may not be supportedget valid channels are not
5234                         //supported
5235                         config.apBand = 0;
5236                         config.apChannel = 6;
5237                     }
5238                 }
5239             }
5240         } else {
5241             //for some old device, wifiHal may not be supported
5242             config.apBand = 0;
5243             config.apChannel = 6;
5244         }
5245         // Start hostapd on a separate thread
5246         new Thread(new Runnable() {
5247             public void run() {
5248                 try {
5249                     mNwService.startAccessPoint(config, mInterfaceName);
5250                 } catch (Exception e) {
5251                     loge("Exception in softap start " + e);
5252                     try {
5253                         mNwService.stopAccessPoint(mInterfaceName);
5254                         mNwService.startAccessPoint(config, mInterfaceName);
5255                     } catch (Exception e1) {
5256                         loge("Exception in softap re-start " + e1);
5257                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
5258                         return;
5259                     }
5260                 }
5261                 if (DBG) log("Soft AP start successful");
5262                 sendMessage(CMD_START_AP_SUCCESS);
5263             }
5264         }).start();
5265     }
5266 
5267     /*
5268      * Read a MAC address in /proc/arp/table, used by WifistateMachine
5269      * so as to record MAC address of default gateway.
5270      **/
macAddressFromRoute(String ipAddress)5271     private String macAddressFromRoute(String ipAddress) {
5272         String macAddress = null;
5273         BufferedReader reader = null;
5274         try {
5275             reader = new BufferedReader(new FileReader("/proc/net/arp"));
5276 
5277             // Skip over the line bearing colum titles
5278             String line = reader.readLine();
5279 
5280             while ((line = reader.readLine()) != null) {
5281                 String[] tokens = line.split("[ ]+");
5282                 if (tokens.length < 6) {
5283                     continue;
5284                 }
5285 
5286                 // ARP column format is
5287                 // Address HWType HWAddress Flags Mask IFace
5288                 String ip = tokens[0];
5289                 String mac = tokens[3];
5290 
5291                 if (ipAddress.equals(ip)) {
5292                     macAddress = mac;
5293                     break;
5294                 }
5295             }
5296 
5297             if (macAddress == null) {
5298                 loge("Did not find remoteAddress {" + ipAddress + "} in " +
5299                         "/proc/net/arp");
5300             }
5301 
5302         } catch (FileNotFoundException e) {
5303             loge("Could not open /proc/net/arp to lookup mac address");
5304         } catch (IOException e) {
5305             loge("Could not read /proc/net/arp to lookup mac address");
5306         } finally {
5307             try {
5308                 if (reader != null) {
5309                     reader.close();
5310                 }
5311             } catch (IOException e) {
5312                 // Do nothing
5313             }
5314         }
5315         return macAddress;
5316 
5317     }
5318 
5319     private class WifiNetworkFactory extends NetworkFactory {
WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f)5320         public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
5321             super(l, c, TAG, f);
5322         }
5323 
5324         @Override
needNetworkFor(NetworkRequest networkRequest, int score)5325         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
5326             ++mConnectionRequests;
5327         }
5328 
5329         @Override
releaseNetworkFor(NetworkRequest networkRequest)5330         protected void releaseNetworkFor(NetworkRequest networkRequest) {
5331             --mConnectionRequests;
5332         }
5333 
dump(FileDescriptor fd, PrintWriter pw, String[] args)5334         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5335             pw.println("mConnectionRequests " + mConnectionRequests);
5336         }
5337 
5338     }
5339 
5340     private class UntrustedWifiNetworkFactory extends NetworkFactory {
5341         private int mUntrustedReqCount;
5342 
UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f)5343         public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
5344             super(l, c, tag, f);
5345         }
5346 
5347         @Override
needNetworkFor(NetworkRequest networkRequest, int score)5348         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
5349             if (!networkRequest.networkCapabilities.hasCapability(
5350                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
5351                 if (++mUntrustedReqCount == 1) {
5352                     mWifiAutoJoinController.setAllowUntrustedConnections(true);
5353                 }
5354             }
5355         }
5356 
5357         @Override
releaseNetworkFor(NetworkRequest networkRequest)5358         protected void releaseNetworkFor(NetworkRequest networkRequest) {
5359             if (!networkRequest.networkCapabilities.hasCapability(
5360                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
5361                 if (--mUntrustedReqCount == 0) {
5362                     mWifiAutoJoinController.setAllowUntrustedConnections(false);
5363                 }
5364             }
5365         }
5366 
dump(FileDescriptor fd, PrintWriter pw, String[] args)5367         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5368             pw.println("mUntrustedReqCount " + mUntrustedReqCount);
5369         }
5370     }
5371 
maybeRegisterNetworkFactory()5372     void maybeRegisterNetworkFactory() {
5373         if (mNetworkFactory == null) {
5374             checkAndSetConnectivityInstance();
5375             if (mCm != null) {
5376                 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
5377                         NETWORKTYPE, mNetworkCapabilitiesFilter);
5378                 mNetworkFactory.setScoreFilter(60);
5379                 mNetworkFactory.register();
5380 
5381                 // We can't filter untrusted network in the capabilities filter because a trusted
5382                 // network would still satisfy a request that accepts untrusted ones.
5383                 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(),
5384                         mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter);
5385                 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE);
5386                 mUntrustedNetworkFactory.register();
5387             }
5388         }
5389     }
5390 
5391     /********************************************************
5392      * HSM states
5393      *******************************************************/
5394 
5395     class DefaultState extends State {
5396         @Override
processMessage(Message message)5397         public boolean processMessage(Message message) {
5398             logStateAndMessage(message, getClass().getSimpleName());
5399 
5400             switch (message.what) {
5401                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
5402                     AsyncChannel ac = (AsyncChannel) message.obj;
5403                     if (ac == mWifiP2pChannel) {
5404                         if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
5405                             mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
5406                         } else {
5407                             loge("WifiP2pService connection failure, error=" + message.arg1);
5408                         }
5409                     } else {
5410                         loge("got HALF_CONNECTED for unknown channel");
5411                     }
5412                     break;
5413                 }
5414                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
5415                     AsyncChannel ac = (AsyncChannel) message.obj;
5416                     if (ac == mWifiP2pChannel) {
5417                         loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
5418                         //TODO: Re-establish connection to state machine after a delay
5419                         // mWifiP2pChannel.connect(mContext, getHandler(),
5420                         // mWifiP2pManager.getMessenger());
5421                     }
5422                     break;
5423                 }
5424                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
5425                     mBluetoothConnectionActive = (message.arg1 !=
5426                             BluetoothAdapter.STATE_DISCONNECTED);
5427                     break;
5428                     /* Synchronous call returns */
5429                 case CMD_PING_SUPPLICANT:
5430                 case CMD_ENABLE_NETWORK:
5431                 case CMD_ADD_OR_UPDATE_NETWORK:
5432                 case CMD_REMOVE_NETWORK:
5433                 case CMD_SAVE_CONFIG:
5434                     replyToMessage(message, message.what, FAILURE);
5435                     break;
5436                 case CMD_GET_CAPABILITY_FREQ:
5437                     replyToMessage(message, message.what, null);
5438                     break;
5439                 case CMD_GET_CONFIGURED_NETWORKS:
5440                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
5441                     break;
5442                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5443                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
5444                     break;
5445                 case CMD_ENABLE_RSSI_POLL:
5446                     mEnableRssiPolling = (message.arg1 == 1);
5447                     break;
5448                 case CMD_SET_HIGH_PERF_MODE:
5449                     if (message.arg1 == 1) {
5450                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
5451                     } else {
5452                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
5453                     }
5454                     break;
5455                 case CMD_BOOT_COMPLETED:
5456                     maybeRegisterNetworkFactory();
5457                     break;
5458                 case CMD_SCREEN_STATE_CHANGED:
5459                     handleScreenStateChanged(message.arg1 != 0);
5460                     break;
5461                     /* Discard */
5462                 case CMD_START_SCAN:
5463                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5464                     break;
5465                 case CMD_START_SUPPLICANT:
5466                 case CMD_STOP_SUPPLICANT:
5467                 case CMD_STOP_SUPPLICANT_FAILED:
5468                 case CMD_START_DRIVER:
5469                 case CMD_STOP_DRIVER:
5470                 case CMD_DELAYED_STOP_DRIVER:
5471                 case CMD_DRIVER_START_TIMED_OUT:
5472                 case CMD_START_AP:
5473                 case CMD_START_AP_SUCCESS:
5474                 case CMD_START_AP_FAILURE:
5475                 case CMD_STOP_AP:
5476                 case CMD_TETHER_STATE_CHANGE:
5477                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
5478                 case CMD_DISCONNECT:
5479                 case CMD_RECONNECT:
5480                 case CMD_REASSOCIATE:
5481                 case CMD_RELOAD_TLS_AND_RECONNECT:
5482                 case WifiMonitor.SUP_CONNECTION_EVENT:
5483                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
5484                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
5485                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5486                 case WifiMonitor.SCAN_RESULTS_EVENT:
5487                 case WifiMonitor.SCAN_FAILED_EVENT:
5488                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5489                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5490                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5491                 case WifiMonitor.WPS_OVERLAP_EVENT:
5492                 case CMD_BLACKLIST_NETWORK:
5493                 case CMD_CLEAR_BLACKLIST:
5494                 case CMD_SET_OPERATIONAL_MODE:
5495                 case CMD_SET_COUNTRY_CODE:
5496                 case CMD_SET_FREQUENCY_BAND:
5497                 case CMD_RSSI_POLL:
5498                 case CMD_ENABLE_ALL_NETWORKS:
5499                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
5500                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
5501                 /* Handled by WifiApConfigStore */
5502                 case CMD_SET_AP_CONFIG:
5503                 case CMD_SET_AP_CONFIG_COMPLETED:
5504                 case CMD_REQUEST_AP_CONFIG:
5505                 case CMD_RESPONSE_AP_CONFIG:
5506                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
5507                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
5508                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
5509                 case CMD_DISABLE_P2P_RSP:
5510                 case WifiMonitor.SUP_REQUEST_IDENTITY:
5511                 case CMD_TEST_NETWORK_DISCONNECT:
5512                 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
5513                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5514                 case CMD_TARGET_BSSID:
5515                 case CMD_AUTO_CONNECT:
5516                 case CMD_AUTO_ROAM:
5517                 case CMD_AUTO_SAVE_NETWORK:
5518                 case CMD_ASSOCIATED_BSSID:
5519                 case CMD_UNWANTED_NETWORK:
5520                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
5521                 case CMD_ROAM_WATCHDOG_TIMER:
5522                 case CMD_DISABLE_EPHEMERAL_NETWORK:
5523                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
5524                 case CMD_STARTED_PNO_DBG:
5525                 case CMD_STARTED_GSCAN_DBG:
5526                 case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
5527                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5528                     break;
5529                 case DhcpStateMachine.CMD_ON_QUIT:
5530                     mDhcpStateMachine = null;
5531                     break;
5532                 case CMD_SET_SUSPEND_OPT_ENABLED:
5533                     if (message.arg1 == 1) {
5534                         mSuspendWakeLock.release();
5535                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
5536                     } else {
5537                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
5538                     }
5539                     break;
5540                 case WifiMonitor.DRIVER_HUNG_EVENT:
5541                     setSupplicantRunning(false);
5542                     setSupplicantRunning(true);
5543                     break;
5544                 case WifiManager.CONNECT_NETWORK:
5545                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5546                             WifiManager.BUSY);
5547                     break;
5548                 case WifiManager.FORGET_NETWORK:
5549                     replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5550                             WifiManager.BUSY);
5551                     break;
5552                 case WifiManager.SAVE_NETWORK:
5553                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5554                     replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5555                             WifiManager.BUSY);
5556                     break;
5557                 case WifiManager.START_WPS:
5558                     replyToMessage(message, WifiManager.WPS_FAILED,
5559                             WifiManager.BUSY);
5560                     break;
5561                 case WifiManager.CANCEL_WPS:
5562                     replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
5563                             WifiManager.BUSY);
5564                     break;
5565                 case WifiManager.DISABLE_NETWORK:
5566                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5567                             WifiManager.BUSY);
5568                     break;
5569                 case WifiManager.RSSI_PKTCNT_FETCH:
5570                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
5571                             WifiManager.BUSY);
5572                     break;
5573                 case CMD_GET_SUPPORTED_FEATURES:
5574                     int featureSet = WifiNative.getSupportedFeatureSet();
5575                     replyToMessage(message, message.what, featureSet);
5576                     break;
5577                 case CMD_FIRMWARE_ALERT:
5578                     if (mWifiLogger != null) {
5579                         byte[] buffer = (byte[])message.obj;
5580                         mWifiLogger.captureAlertData(message.arg1, buffer);
5581                     }
5582                     break;
5583                 case CMD_GET_LINK_LAYER_STATS:
5584                     // Not supported hence reply with error message
5585                     replyToMessage(message, message.what, null);
5586                     break;
5587                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
5588                     NetworkInfo info = (NetworkInfo) message.obj;
5589                     mP2pConnected.set(info.isConnected());
5590                     break;
5591                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5592                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
5593                     replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
5594                     break;
5595                 /* Link configuration (IP address, DNS, ...) changes notified via netlink */
5596                 case CMD_UPDATE_LINKPROPERTIES:
5597                     updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
5598                     break;
5599                 case CMD_GET_MATCHING_CONFIG:
5600                     replyToMessage(message, message.what);
5601                     break;
5602                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
5603                 case CMD_IP_CONFIGURATION_LOST:
5604                 case CMD_IP_REACHABILITY_LOST:
5605                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5606                     break;
5607                 case CMD_GET_CONNECTION_STATISTICS:
5608                     replyToMessage(message, message.what, mWifiConnectionStatistics);
5609                     break;
5610                 case CMD_REMOVE_APP_CONFIGURATIONS:
5611                     deferMessage(message);
5612                     break;
5613                 case CMD_REMOVE_USER_CONFIGURATIONS:
5614                     deferMessage(message);
5615                     break;
5616                 default:
5617                     loge("Error! unhandled message" + message);
5618                     break;
5619             }
5620             return HANDLED;
5621         }
5622     }
5623 
5624     class InitialState extends State {
5625         @Override
enter()5626         public void enter() {
5627             WifiNative.stopHal();
5628             mWifiNative.unloadDriver();
5629             if (mWifiP2pChannel == null) {
5630                 mWifiP2pChannel = new AsyncChannel();
5631                 mWifiP2pChannel.connect(mContext, getHandler(),
5632                     mWifiP2pServiceImpl.getP2pStateMachineMessenger());
5633             }
5634 
5635             if (mWifiApConfigChannel == null) {
5636                 mWifiApConfigChannel = new AsyncChannel();
5637                 mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
5638                         mContext, getHandler());
5639                 mWifiApConfigStore.loadApConfiguration();
5640                 mWifiApConfigChannel.connectSync(mContext, getHandler(),
5641                         mWifiApConfigStore.getMessenger());
5642             }
5643 
5644             if (mWifiConfigStore.enableHalBasedPno.get()) {
5645                 // make sure developer Settings are in sync with the config option
5646                 mHalBasedPnoEnableInDevSettings = true;
5647             }
5648         }
5649         @Override
processMessage(Message message)5650         public boolean processMessage(Message message) {
5651             logStateAndMessage(message, getClass().getSimpleName());
5652             switch (message.what) {
5653                 case CMD_START_SUPPLICANT:
5654                     if (mWifiNative.loadDriver()) {
5655                         try {
5656                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
5657                         } catch (Exception e) {
5658                             loge("Failed to reload STA firmware " + e);
5659                             // Continue
5660                         }
5661 
5662                         try {
5663                             // A runtime crash can leave the interface up and
5664                             // IP addresses configured, and this affects
5665                             // connectivity when supplicant starts up.
5666                             // Ensure interface is down and we have no IP
5667                             // addresses before a supplicant start.
5668                             mNwService.setInterfaceDown(mInterfaceName);
5669                             mNwService.clearInterfaceAddresses(mInterfaceName);
5670 
5671                             // Set privacy extensions
5672                             mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
5673 
5674                             // IPv6 is enabled only as long as access point is connected since:
5675                             // - IPv6 addresses and routes stick around after disconnection
5676                             // - kernel is unaware when connected and fails to start IPv6 negotiation
5677                             // - kernel can start autoconfiguration when 802.1x is not complete
5678                             mNwService.disableIpv6(mInterfaceName);
5679                         } catch (RemoteException re) {
5680                             loge("Unable to change interface settings: " + re);
5681                         } catch (IllegalStateException ie) {
5682                             loge("Unable to change interface settings: " + ie);
5683                         }
5684 
5685                        /* Stop a running supplicant after a runtime restart
5686                         * Avoids issues with drivers that do not handle interface down
5687                         * on a running supplicant properly.
5688                         */
5689                         mWifiMonitor.killSupplicant(mP2pSupported);
5690 
5691                         if (WifiNative.startHal() == false) {
5692                             /* starting HAL is optional */
5693                             loge("Failed to start HAL");
5694                         }
5695 
5696                         if (mWifiNative.startSupplicant(mP2pSupported)) {
5697                             setWifiState(WIFI_STATE_ENABLING);
5698                             if (DBG) log("Supplicant start successful");
5699                             mWifiMonitor.startMonitoring();
5700                             transitionTo(mSupplicantStartingState);
5701                         } else {
5702                             loge("Failed to start supplicant!");
5703                         }
5704                     } else {
5705                         loge("Failed to load driver");
5706                     }
5707                     break;
5708                 case CMD_START_AP:
5709                     if (mWifiNative.loadDriver() == false) {
5710                         loge("Failed to load driver for softap");
5711                     } else {
5712                         if (enableSoftAp() == true) {
5713                             setWifiApState(WIFI_AP_STATE_ENABLING, 0);
5714                             transitionTo(mSoftApStartingState);
5715                         } else {
5716                             setWifiApState(WIFI_AP_STATE_FAILED,
5717                                     WifiManager.SAP_START_FAILURE_GENERAL);
5718                             transitionTo(mInitialState);
5719                         }
5720                     }
5721                     break;
5722                 default:
5723                     return NOT_HANDLED;
5724             }
5725             return HANDLED;
5726         }
5727     }
5728 
5729     class SupplicantStartingState extends State {
initializeWpsDetails()5730         private void initializeWpsDetails() {
5731             String detail;
5732             detail = SystemProperties.get("ro.product.name", "");
5733             if (!mWifiNative.setDeviceName(detail)) {
5734                 loge("Failed to set device name " +  detail);
5735             }
5736             detail = SystemProperties.get("ro.product.manufacturer", "");
5737             if (!mWifiNative.setManufacturer(detail)) {
5738                 loge("Failed to set manufacturer " + detail);
5739             }
5740             detail = SystemProperties.get("ro.product.model", "");
5741             if (!mWifiNative.setModelName(detail)) {
5742                 loge("Failed to set model name " + detail);
5743             }
5744             detail = SystemProperties.get("ro.product.model", "");
5745             if (!mWifiNative.setModelNumber(detail)) {
5746                 loge("Failed to set model number " + detail);
5747             }
5748             detail = SystemProperties.get("ro.serialno", "");
5749             if (!mWifiNative.setSerialNumber(detail)) {
5750                 loge("Failed to set serial number " + detail);
5751             }
5752             if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
5753                 loge("Failed to set WPS config methods");
5754             }
5755             if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
5756                 loge("Failed to set primary device type " + mPrimaryDeviceType);
5757             }
5758         }
5759 
5760         @Override
processMessage(Message message)5761         public boolean processMessage(Message message) {
5762             logStateAndMessage(message, getClass().getSimpleName());
5763 
5764             switch(message.what) {
5765                 case WifiMonitor.SUP_CONNECTION_EVENT:
5766                     if (DBG) log("Supplicant connection established");
5767                     setWifiState(WIFI_STATE_ENABLED);
5768                     mSupplicantRestartCount = 0;
5769                     /* Reset the supplicant state to indicate the supplicant
5770                      * state is not known at this time */
5771                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5772                     /* Initialize data structures */
5773                     mLastBssid = null;
5774                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
5775                     mLastSignalLevel = -1;
5776 
5777                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
5778                     /* set frequency band of operation */
5779                     setFrequencyBand();
5780                     mWifiNative.enableSaveConfig();
5781                     mWifiConfigStore.loadAndEnableAllNetworks();
5782                     if (mWifiConfigStore.enableVerboseLogging.get() > 0) {
5783                         enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get());
5784                     }
5785                     initializeWpsDetails();
5786 
5787                     sendSupplicantConnectionChangedBroadcast(true);
5788                     transitionTo(mDriverStartedState);
5789                     break;
5790                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
5791                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
5792                         loge("Failed to setup control channel, restart supplicant");
5793                         mWifiMonitor.killSupplicant(mP2pSupported);
5794                         transitionTo(mInitialState);
5795                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5796                     } else {
5797                         loge("Failed " + mSupplicantRestartCount +
5798                                 " times to start supplicant, unload driver");
5799                         mSupplicantRestartCount = 0;
5800                         setWifiState(WIFI_STATE_UNKNOWN);
5801                         transitionTo(mInitialState);
5802                     }
5803                     break;
5804                 case CMD_START_SUPPLICANT:
5805                 case CMD_STOP_SUPPLICANT:
5806                 case CMD_START_AP:
5807                 case CMD_STOP_AP:
5808                 case CMD_START_DRIVER:
5809                 case CMD_STOP_DRIVER:
5810                 case CMD_SET_OPERATIONAL_MODE:
5811                 case CMD_SET_COUNTRY_CODE:
5812                 case CMD_SET_FREQUENCY_BAND:
5813                 case CMD_START_PACKET_FILTERING:
5814                 case CMD_STOP_PACKET_FILTERING:
5815                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5816                     deferMessage(message);
5817                     break;
5818                 default:
5819                     return NOT_HANDLED;
5820             }
5821             return HANDLED;
5822         }
5823     }
5824 
5825     class SupplicantStartedState extends State {
5826         @Override
enter()5827         public void enter() {
5828             /* Wifi is available as long as we have a connection to supplicant */
5829             mNetworkInfo.setIsAvailable(true);
5830             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5831 
5832             int defaultInterval = mContext.getResources().getInteger(
5833                     R.integer.config_wifi_supplicant_scan_interval);
5834 
5835             mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
5836                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
5837                     defaultInterval);
5838 
5839             mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
5840             mWifiNative.setExternalSim(true);
5841 
5842             /* turn on use of DFS channels */
5843             WifiNative.setDfsFlag(true);
5844 
5845             /* set country code */
5846             setCountryCode();
5847 
5848             setRandomMacOui();
5849             mWifiNative.enableAutoConnect(false);
5850         }
5851 
5852         @Override
processMessage(Message message)5853         public boolean processMessage(Message message) {
5854             logStateAndMessage(message, getClass().getSimpleName());
5855 
5856             switch(message.what) {
5857                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
5858                     if (mP2pSupported) {
5859                         transitionTo(mWaitForP2pDisableState);
5860                     } else {
5861                         transitionTo(mSupplicantStoppingState);
5862                     }
5863                     break;
5864                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
5865                     loge("Connection lost, restart supplicant");
5866                     handleSupplicantConnectionLoss(true);
5867                     handleNetworkDisconnect();
5868                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5869                     if (mP2pSupported) {
5870                         transitionTo(mWaitForP2pDisableState);
5871                     } else {
5872                         transitionTo(mInitialState);
5873                     }
5874                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5875                     break;
5876                 case WifiMonitor.SCAN_RESULTS_EVENT:
5877                 case WifiMonitor.SCAN_FAILED_EVENT:
5878                     maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
5879                     closeRadioScanStats();
5880                     noteScanEnd();
5881                     setScanResults();
5882                     if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
5883                         /* Just updated results from full scan, let apps know about this */
5884                         boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
5885                         sendScanResultsAvailableBroadcast(scanSucceeded);
5886                     }
5887                     mSendScanResultsBroadcast = false;
5888                     mIsScanOngoing = false;
5889                     mIsFullScanOngoing = false;
5890                     if (mBufferedScanMsg.size() > 0)
5891                         sendMessage(mBufferedScanMsg.remove());
5892                     break;
5893                 case CMD_PING_SUPPLICANT:
5894                     boolean ok = mWifiNative.ping();
5895                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5896                     break;
5897                 case CMD_GET_CAPABILITY_FREQ:
5898                     String freqs = mWifiNative.getFreqCapability();
5899                     replyToMessage(message, message.what, freqs);
5900                     break;
5901                 case CMD_START_AP:
5902                     /* Cannot start soft AP while in client mode */
5903                     loge("Failed to start soft AP with a running supplicant");
5904                     setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
5905                     break;
5906                 case CMD_SET_OPERATIONAL_MODE:
5907                     mOperationalMode = message.arg1;
5908                     mWifiConfigStore.
5909                             setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
5910                     break;
5911                 case CMD_TARGET_BSSID:
5912                     // Trying to associate to this BSSID
5913                     if (message.obj != null) {
5914                         mTargetRoamBSSID = (String) message.obj;
5915                     }
5916                     break;
5917                 case CMD_GET_LINK_LAYER_STATS:
5918                     WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
5919                     if (stats == null) {
5920                         // When firmware doesnt support link layer stats, return an empty object
5921                         stats = new WifiLinkLayerStats();
5922                     }
5923                     replyToMessage(message, message.what, stats);
5924                     break;
5925                 case CMD_SET_COUNTRY_CODE:
5926                     String country = (String) message.obj;
5927 
5928                     final boolean persist = (message.arg2 == 1);
5929                     final int sequence = message.arg1;
5930 
5931                     if (sequence != mCountryCodeSequence.get()) {
5932                         if (DBG) log("set country code ignored due to sequnce num");
5933                         break;
5934                     }
5935                     if (DBG) log("set country code " + country);
5936                     country = country.toUpperCase(Locale.ROOT);
5937 
5938                     if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) {
5939                         if (mWifiNative.setCountryCode(country)) {
5940                             mDriverSetCountryCode = country;
5941                         } else {
5942                             loge("Failed to set country code " + country);
5943                         }
5944                     }
5945 
5946                     mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country);
5947                     break;
5948                 default:
5949                     return NOT_HANDLED;
5950             }
5951             return HANDLED;
5952         }
5953 
5954         @Override
exit()5955         public void exit() {
5956             mNetworkInfo.setIsAvailable(false);
5957             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5958         }
5959     }
5960 
5961     class SupplicantStoppingState extends State {
5962         @Override
enter()5963         public void enter() {
5964             /* Send any reset commands to supplicant before shutting it down */
5965             handleNetworkDisconnect();
5966             if (mDhcpStateMachine != null) {
5967                 mDhcpStateMachine.doQuit();
5968             }
5969 
5970             String suppState = System.getProperty("init.svc.wpa_supplicant");
5971             if (suppState == null) suppState = "unknown";
5972             String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");
5973             if (p2pSuppState == null) p2pSuppState = "unknown";
5974 
5975             logd("SupplicantStoppingState: stopSupplicant "
5976                     + " init.svc.wpa_supplicant=" + suppState
5977                     + " init.svc.p2p_supplicant=" + p2pSuppState);
5978             mWifiMonitor.stopSupplicant();
5979 
5980             /* Send ourselves a delayed message to indicate failure after a wait time */
5981             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
5982                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
5983             setWifiState(WIFI_STATE_DISABLING);
5984             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5985         }
5986         @Override
processMessage(Message message)5987         public boolean processMessage(Message message) {
5988             logStateAndMessage(message, getClass().getSimpleName());
5989 
5990             switch(message.what) {
5991                 case WifiMonitor.SUP_CONNECTION_EVENT:
5992                     loge("Supplicant connection received while stopping");
5993                     break;
5994                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
5995                     if (DBG) log("Supplicant connection lost");
5996                     handleSupplicantConnectionLoss(false);
5997                     transitionTo(mInitialState);
5998                     break;
5999                 case CMD_STOP_SUPPLICANT_FAILED:
6000                     if (message.arg1 == mSupplicantStopFailureToken) {
6001                         loge("Timed out on a supplicant stop, kill and proceed");
6002                         handleSupplicantConnectionLoss(true);
6003                         transitionTo(mInitialState);
6004                     }
6005                     break;
6006                 case CMD_START_SUPPLICANT:
6007                 case CMD_STOP_SUPPLICANT:
6008                 case CMD_START_AP:
6009                 case CMD_STOP_AP:
6010                 case CMD_START_DRIVER:
6011                 case CMD_STOP_DRIVER:
6012                 case CMD_SET_OPERATIONAL_MODE:
6013                 case CMD_SET_COUNTRY_CODE:
6014                 case CMD_SET_FREQUENCY_BAND:
6015                 case CMD_START_PACKET_FILTERING:
6016                 case CMD_STOP_PACKET_FILTERING:
6017                     deferMessage(message);
6018                     break;
6019                 default:
6020                     return NOT_HANDLED;
6021             }
6022             return HANDLED;
6023         }
6024     }
6025 
6026     class DriverStartingState extends State {
6027         private int mTries;
6028         @Override
enter()6029         public void enter() {
6030             mTries = 1;
6031             /* Send ourselves a delayed message to start driver a second time */
6032             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
6033                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
6034         }
6035         @Override
processMessage(Message message)6036         public boolean processMessage(Message message) {
6037             logStateAndMessage(message, getClass().getSimpleName());
6038 
6039             switch(message.what) {
6040                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6041                     SupplicantState state = handleSupplicantStateChange(message);
6042                     /* If suplicant is exiting out of INTERFACE_DISABLED state into
6043                      * a state that indicates driver has started, it is ready to
6044                      * receive driver commands
6045                      */
6046                     if (SupplicantState.isDriverActive(state)) {
6047                         transitionTo(mDriverStartedState);
6048                     }
6049                     break;
6050                 case CMD_DRIVER_START_TIMED_OUT:
6051                     if (message.arg1 == mDriverStartToken) {
6052                         if (mTries >= 2) {
6053                             loge("Failed to start driver after " + mTries);
6054                             transitionTo(mDriverStoppedState);
6055                         } else {
6056                             loge("Driver start failed, retrying");
6057                             mWakeLock.acquire();
6058                             mWifiNative.startDriver();
6059                             mWakeLock.release();
6060 
6061                             ++mTries;
6062                             /* Send ourselves a delayed message to start driver again */
6063                             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
6064                                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
6065                         }
6066                     }
6067                     break;
6068                     /* Queue driver commands & connection events */
6069                 case CMD_START_DRIVER:
6070                 case CMD_STOP_DRIVER:
6071                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
6072                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6073                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6074                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6075                 case WifiMonitor.WPS_OVERLAP_EVENT:
6076                 case CMD_SET_COUNTRY_CODE:
6077                 case CMD_SET_FREQUENCY_BAND:
6078                 case CMD_START_PACKET_FILTERING:
6079                 case CMD_STOP_PACKET_FILTERING:
6080                 case CMD_START_SCAN:
6081                 case CMD_DISCONNECT:
6082                 case CMD_REASSOCIATE:
6083                 case CMD_RECONNECT:
6084                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6085                     deferMessage(message);
6086                     break;
6087                 case WifiMonitor.SCAN_RESULTS_EVENT:
6088                 case WifiMonitor.SCAN_FAILED_EVENT:
6089                     // Loose scan results obtained in Driver Starting state, they can only confuse
6090                     // the state machine
6091                     break;
6092                 default:
6093                     return NOT_HANDLED;
6094             }
6095             return HANDLED;
6096         }
6097     }
6098 
6099     class DriverStartedState extends State {
6100         @Override
enter()6101         public void enter() {
6102 
6103             if (PDBG) {
6104                 logd("DriverStartedState enter");
6105             }
6106 
6107             mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
6108             mIsRunning = true;
6109             mInDelayedStop = false;
6110             mDelayedStopCounter++;
6111             updateBatteryWorkSource(null);
6112             /**
6113              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
6114              * When this mode is on, some of the low-level scan parameters used by the
6115              * driver are changed to reduce interference with bluetooth
6116              */
6117             mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
6118             /* initialize network state */
6119             setNetworkDetailedState(DetailedState.DISCONNECTED);
6120 
6121             /* Remove any filtering on Multicast v6 at start */
6122             mWifiNative.stopFilteringMulticastV6Packets();
6123 
6124             /* Reset Multicast v4 filtering state */
6125             if (mFilteringMulticastV4Packets.get()) {
6126                 mWifiNative.startFilteringMulticastV4Packets();
6127             } else {
6128                 mWifiNative.stopFilteringMulticastV4Packets();
6129             }
6130 
6131             mDhcpActive = false;
6132 
6133             if (mOperationalMode != CONNECT_MODE) {
6134                 mWifiNative.disconnect();
6135                 mWifiConfigStore.disableAllNetworks();
6136                 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6137                     setWifiState(WIFI_STATE_DISABLED);
6138                 }
6139                 transitionTo(mScanModeState);
6140             } else {
6141 
6142                 // Status pulls in the current supplicant state and network connection state
6143                 // events over the monitor connection. This helps framework sync up with
6144                 // current supplicant state
6145                 // TODO: actually check th supplicant status string and make sure the supplicant
6146                 // is in disconnecte4d state.
6147                 mWifiNative.status();
6148                 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
6149                 transitionTo(mDisconnectedState);
6150                 transitionTo(mDisconnectedState);
6151             }
6152 
6153             // We may have missed screen update at boot
6154             if (mScreenBroadcastReceived.get() == false) {
6155                 PowerManager powerManager = (PowerManager)mContext.getSystemService(
6156                         Context.POWER_SERVICE);
6157                 handleScreenStateChanged(powerManager.isScreenOn());
6158             } else {
6159                 // Set the right suspend mode settings
6160                 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
6161                         && mUserWantsSuspendOpt.get());
6162             }
6163             mWifiNative.setPowerSave(true);
6164 
6165             if (mP2pSupported) {
6166                 if (mOperationalMode == CONNECT_MODE) {
6167                     mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
6168                 } else {
6169                     // P2P statemachine starts in disabled state, and is not enabled until
6170                     // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
6171                     // keep it disabled.
6172                 }
6173             }
6174 
6175             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
6176             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
6177             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
6178             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
6179 
6180             mHalFeatureSet = WifiNative.getSupportedFeatureSet();
6181             if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO)
6182                     == WifiManager.WIFI_FEATURE_HAL_EPNO) {
6183                 mHalBasedPnoDriverSupported = true;
6184             }
6185 
6186             // Enable link layer stats gathering
6187             mWifiNative.setWifiLinkLayerStats("wlan0", 1);
6188 
6189             if (PDBG) {
6190                 logd("Driverstarted State enter done, epno=" + mHalBasedPnoDriverSupported
6191                      + " feature=" + mHalFeatureSet);
6192             }
6193         }
6194 
6195         @Override
processMessage(Message message)6196         public boolean processMessage(Message message) {
6197             logStateAndMessage(message, getClass().getSimpleName());
6198 
6199             switch(message.what) {
6200                 case CMD_START_SCAN:
6201                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
6202                     break;
6203                 case CMD_SET_FREQUENCY_BAND:
6204                     int band =  message.arg1;
6205                     if (DBG) log("set frequency band " + band);
6206                     if (mWifiNative.setBand(band)) {
6207 
6208                         if (PDBG)  logd("did set frequency band " + band);
6209 
6210                         mFrequencyBand.set(band);
6211                         // Flush old data - like scan results
6212                         mWifiNative.bssFlush();
6213                         // Fetch the latest scan results when frequency band is set
6214 //                        startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
6215 
6216                         if (PDBG)  logd("done set frequency band " + band);
6217 
6218                     } else {
6219                         loge("Failed to set frequency band " + band);
6220                     }
6221                     break;
6222                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
6223                     mBluetoothConnectionActive = (message.arg1 !=
6224                             BluetoothAdapter.STATE_DISCONNECTED);
6225                     mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
6226                     break;
6227                 case CMD_STOP_DRIVER:
6228                     int mode = message.arg1;
6229 
6230                     /* Already doing a delayed stop */
6231                     if (mInDelayedStop) {
6232                         if (DBG) log("Already in delayed stop");
6233                         break;
6234                     }
6235                     /* disconnect right now, but leave the driver running for a bit */
6236                     mWifiConfigStore.disableAllNetworks();
6237 
6238                     mInDelayedStop = true;
6239                     mDelayedStopCounter++;
6240                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
6241 
6242                     /* send regular delayed shut down */
6243                     Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
6244                     driverStopIntent.setPackage(this.getClass().getPackage().getName());
6245                     driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
6246                     mDriverStopIntent = PendingIntent.getBroadcast(mContext,
6247                             DRIVER_STOP_REQUEST, driverStopIntent,
6248                             PendingIntent.FLAG_UPDATE_CURRENT);
6249 
6250                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
6251                             + mDriverStopDelayMs, mDriverStopIntent);
6252                     break;
6253                 case CMD_START_DRIVER:
6254                     if (mInDelayedStop) {
6255                         mInDelayedStop = false;
6256                         mDelayedStopCounter++;
6257                         mAlarmManager.cancel(mDriverStopIntent);
6258                         if (DBG) log("Delayed stop ignored due to start");
6259                         if (mOperationalMode == CONNECT_MODE) {
6260                             mWifiConfigStore.enableAllNetworks();
6261                         }
6262                     }
6263                     break;
6264                 case CMD_DELAYED_STOP_DRIVER:
6265                     if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
6266                     if (message.arg1 != mDelayedStopCounter) break;
6267                     if (getCurrentState() != mDisconnectedState) {
6268                         mWifiNative.disconnect();
6269                         handleNetworkDisconnect();
6270                     }
6271                     mWakeLock.acquire();
6272                     mWifiNative.stopDriver();
6273                     mWakeLock.release();
6274                     if (mP2pSupported) {
6275                         transitionTo(mWaitForP2pDisableState);
6276                     } else {
6277                         transitionTo(mDriverStoppingState);
6278                     }
6279                     break;
6280                 case CMD_START_PACKET_FILTERING:
6281                     if (message.arg1 == MULTICAST_V6) {
6282                         mWifiNative.startFilteringMulticastV6Packets();
6283                     } else if (message.arg1 == MULTICAST_V4) {
6284                         mWifiNative.startFilteringMulticastV4Packets();
6285                     } else {
6286                         loge("Illegal arugments to CMD_START_PACKET_FILTERING");
6287                     }
6288                     break;
6289                 case CMD_STOP_PACKET_FILTERING:
6290                     if (message.arg1 == MULTICAST_V6) {
6291                         mWifiNative.stopFilteringMulticastV6Packets();
6292                     } else if (message.arg1 == MULTICAST_V4) {
6293                         mWifiNative.stopFilteringMulticastV4Packets();
6294                     } else {
6295                         loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
6296                     }
6297                     break;
6298                 case CMD_SET_SUSPEND_OPT_ENABLED:
6299                     if (message.arg1 == 1) {
6300                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
6301                         mSuspendWakeLock.release();
6302                     } else {
6303                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
6304                     }
6305                     break;
6306                 case CMD_SET_HIGH_PERF_MODE:
6307                     if (message.arg1 == 1) {
6308                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
6309                     } else {
6310                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
6311                     }
6312                     break;
6313                 case CMD_ENABLE_TDLS:
6314                     if (message.obj != null) {
6315                         String remoteAddress = (String) message.obj;
6316                         boolean enable = (message.arg1 == 1);
6317                         mWifiNative.startTdls(remoteAddress, enable);
6318                     }
6319                     break;
6320                 case WifiMonitor.ANQP_DONE_EVENT:
6321                     mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0);
6322                     break;
6323                 default:
6324                     return NOT_HANDLED;
6325             }
6326             return HANDLED;
6327         }
6328         @Override
exit()6329         public void exit() {
6330 
6331             mWifiLogger.stopLogging();
6332 
6333             mIsRunning = false;
6334             updateBatteryWorkSource(null);
6335             mScanResults = new ArrayList<>();
6336 
6337             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
6338             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
6339             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
6340             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
6341             noteScanEnd(); // wrap up any pending request.
6342             mBufferedScanMsg.clear();
6343         }
6344     }
6345 
6346     class WaitForP2pDisableState extends State {
6347         private State mTransitionToState;
6348         @Override
enter()6349         public void enter() {
6350             switch (getCurrentMessage().what) {
6351                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
6352                     mTransitionToState = mInitialState;
6353                     break;
6354                 case CMD_DELAYED_STOP_DRIVER:
6355                     mTransitionToState = mDriverStoppingState;
6356                     break;
6357                 case CMD_STOP_SUPPLICANT:
6358                     mTransitionToState = mSupplicantStoppingState;
6359                     break;
6360                 default:
6361                     mTransitionToState = mDriverStoppingState;
6362                     break;
6363             }
6364             mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
6365         }
6366         @Override
processMessage(Message message)6367         public boolean processMessage(Message message) {
6368             logStateAndMessage(message, getClass().getSimpleName());
6369 
6370             switch(message.what) {
6371                 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
6372                     transitionTo(mTransitionToState);
6373                     break;
6374                 /* Defer wifi start/shut and driver commands */
6375                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6376                 case CMD_START_SUPPLICANT:
6377                 case CMD_STOP_SUPPLICANT:
6378                 case CMD_START_AP:
6379                 case CMD_STOP_AP:
6380                 case CMD_START_DRIVER:
6381                 case CMD_STOP_DRIVER:
6382                 case CMD_SET_OPERATIONAL_MODE:
6383                 case CMD_SET_COUNTRY_CODE:
6384                 case CMD_SET_FREQUENCY_BAND:
6385                 case CMD_START_PACKET_FILTERING:
6386                 case CMD_STOP_PACKET_FILTERING:
6387                 case CMD_START_SCAN:
6388                 case CMD_DISCONNECT:
6389                 case CMD_REASSOCIATE:
6390                 case CMD_RECONNECT:
6391                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6392                     deferMessage(message);
6393                     break;
6394                 default:
6395                     return NOT_HANDLED;
6396             }
6397             return HANDLED;
6398         }
6399     }
6400 
6401     class DriverStoppingState extends State {
6402         @Override
processMessage(Message message)6403         public boolean processMessage(Message message) {
6404             logStateAndMessage(message, getClass().getSimpleName());
6405 
6406             switch(message.what) {
6407                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6408                     SupplicantState state = handleSupplicantStateChange(message);
6409                     if (state == SupplicantState.INTERFACE_DISABLED) {
6410                         transitionTo(mDriverStoppedState);
6411                     }
6412                     break;
6413                     /* Queue driver commands */
6414                 case CMD_START_DRIVER:
6415                 case CMD_STOP_DRIVER:
6416                 case CMD_SET_COUNTRY_CODE:
6417                 case CMD_SET_FREQUENCY_BAND:
6418                 case CMD_START_PACKET_FILTERING:
6419                 case CMD_STOP_PACKET_FILTERING:
6420                 case CMD_START_SCAN:
6421                 case CMD_DISCONNECT:
6422                 case CMD_REASSOCIATE:
6423                 case CMD_RECONNECT:
6424                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6425                     deferMessage(message);
6426                     break;
6427                 default:
6428                     return NOT_HANDLED;
6429             }
6430             return HANDLED;
6431         }
6432     }
6433 
6434     class DriverStoppedState extends State {
6435         @Override
processMessage(Message message)6436         public boolean processMessage(Message message) {
6437             logStateAndMessage(message, getClass().getSimpleName());
6438             switch (message.what) {
6439                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6440                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6441                     SupplicantState state = stateChangeResult.state;
6442                     // A WEXT bug means that we can be back to driver started state
6443                     // unexpectedly
6444                     if (SupplicantState.isDriverActive(state)) {
6445                         transitionTo(mDriverStartedState);
6446                     }
6447                     break;
6448                 case CMD_START_DRIVER:
6449                     mWakeLock.acquire();
6450                     mWifiNative.startDriver();
6451                     mWakeLock.release();
6452                     transitionTo(mDriverStartingState);
6453                     break;
6454                 default:
6455                     return NOT_HANDLED;
6456             }
6457             return HANDLED;
6458         }
6459     }
6460 
6461     class ScanModeState extends State {
6462         private int mLastOperationMode;
6463         @Override
enter()6464         public void enter() {
6465             mLastOperationMode = mOperationalMode;
6466         }
6467         @Override
processMessage(Message message)6468         public boolean processMessage(Message message) {
6469             logStateAndMessage(message, getClass().getSimpleName());
6470 
6471             switch(message.what) {
6472                 case CMD_SET_OPERATIONAL_MODE:
6473                     if (message.arg1 == CONNECT_MODE) {
6474 
6475                         if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6476                             setWifiState(WIFI_STATE_ENABLED);
6477                             // Load and re-enable networks when going back to enabled state
6478                             // This is essential for networks to show up after restore
6479                             mWifiConfigStore.loadAndEnableAllNetworks();
6480                             mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
6481                         } else {
6482                             mWifiConfigStore.enableAllNetworks();
6483                         }
6484 
6485                         // Try autojoining with recent network already present in the cache
6486                         // If none are found then trigger a scan which will trigger autojoin
6487                         // upon reception of scan results event
6488                         if (!mWifiAutoJoinController.attemptAutoJoin()) {
6489                             startScan(ENABLE_WIFI, 0, null, null);
6490                         }
6491 
6492                         // Loose last selection choice since user toggled WiFi
6493                         mWifiConfigStore.
6494                                 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
6495 
6496                         mOperationalMode = CONNECT_MODE;
6497                         transitionTo(mDisconnectedState);
6498                     } else {
6499                         // Nothing to do
6500                         return HANDLED;
6501                     }
6502                     break;
6503                 // Handle scan. All the connection related commands are
6504                 // handled only in ConnectModeState
6505                 case CMD_START_SCAN:
6506                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
6507                     break;
6508                 default:
6509                     return NOT_HANDLED;
6510             }
6511             return HANDLED;
6512         }
6513     }
6514 
6515 
smToString(Message message)6516     String smToString(Message message) {
6517         return smToString(message.what);
6518     }
6519 
smToString(int what)6520     String smToString(int what) {
6521         String s = "unknown";
6522         switch (what) {
6523             case WifiMonitor.DRIVER_HUNG_EVENT:
6524                 s = "DRIVER_HUNG_EVENT";
6525                 break;
6526             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
6527                 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
6528                 break;
6529             case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
6530                 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
6531                 break;
6532             case CMD_SET_FREQUENCY_BAND:
6533                 s = "CMD_SET_FREQUENCY_BAND";
6534                 break;
6535             case CMD_DELAYED_NETWORK_DISCONNECT:
6536                 s = "CMD_DELAYED_NETWORK_DISCONNECT";
6537                 break;
6538             case CMD_TEST_NETWORK_DISCONNECT:
6539                 s = "CMD_TEST_NETWORK_DISCONNECT";
6540                 break;
6541             case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
6542                 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER";
6543                 break;
6544             case CMD_DISABLE_EPHEMERAL_NETWORK:
6545                 s = "CMD_DISABLE_EPHEMERAL_NETWORK";
6546                 break;
6547             case CMD_START_DRIVER:
6548                 s = "CMD_START_DRIVER";
6549                 break;
6550             case CMD_STOP_DRIVER:
6551                 s = "CMD_STOP_DRIVER";
6552                 break;
6553             case CMD_STOP_SUPPLICANT:
6554                 s = "CMD_STOP_SUPPLICANT";
6555                 break;
6556             case CMD_STOP_SUPPLICANT_FAILED:
6557                 s = "CMD_STOP_SUPPLICANT_FAILED";
6558                 break;
6559             case CMD_START_SUPPLICANT:
6560                 s = "CMD_START_SUPPLICANT";
6561                 break;
6562             case CMD_REQUEST_AP_CONFIG:
6563                 s = "CMD_REQUEST_AP_CONFIG";
6564                 break;
6565             case CMD_RESPONSE_AP_CONFIG:
6566                 s = "CMD_RESPONSE_AP_CONFIG";
6567                 break;
6568             case CMD_TETHER_STATE_CHANGE:
6569                 s = "CMD_TETHER_STATE_CHANGE";
6570                 break;
6571             case CMD_TETHER_NOTIFICATION_TIMED_OUT:
6572                 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT";
6573                 break;
6574             case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
6575                 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE";
6576                 break;
6577             case CMD_ADD_OR_UPDATE_NETWORK:
6578                 s = "CMD_ADD_OR_UPDATE_NETWORK";
6579                 break;
6580             case CMD_REMOVE_NETWORK:
6581                 s = "CMD_REMOVE_NETWORK";
6582                 break;
6583             case CMD_ENABLE_NETWORK:
6584                 s = "CMD_ENABLE_NETWORK";
6585                 break;
6586             case CMD_ENABLE_ALL_NETWORKS:
6587                 s = "CMD_ENABLE_ALL_NETWORKS";
6588                 break;
6589             case CMD_AUTO_CONNECT:
6590                 s = "CMD_AUTO_CONNECT";
6591                 break;
6592             case CMD_AUTO_ROAM:
6593                 s = "CMD_AUTO_ROAM";
6594                 break;
6595             case CMD_AUTO_SAVE_NETWORK:
6596                 s = "CMD_AUTO_SAVE_NETWORK";
6597                 break;
6598             case CMD_BOOT_COMPLETED:
6599                 s = "CMD_BOOT_COMPLETED";
6600                 break;
6601             case DhcpStateMachine.CMD_START_DHCP:
6602                 s = "CMD_START_DHCP";
6603                 break;
6604             case DhcpStateMachine.CMD_STOP_DHCP:
6605                 s = "CMD_STOP_DHCP";
6606                 break;
6607             case DhcpStateMachine.CMD_RENEW_DHCP:
6608                 s = "CMD_RENEW_DHCP";
6609                 break;
6610             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
6611                 s = "CMD_PRE_DHCP_ACTION";
6612                 break;
6613             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
6614                 s = "CMD_POST_DHCP_ACTION";
6615                 break;
6616             case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
6617                 s = "CMD_PRE_DHCP_ACTION_COMPLETE";
6618                 break;
6619             case DhcpStateMachine.CMD_ON_QUIT:
6620                 s = "CMD_ON_QUIT";
6621                 break;
6622             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6623                 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
6624                 break;
6625             case WifiManager.DISABLE_NETWORK:
6626                 s = "WifiManager.DISABLE_NETWORK";
6627                 break;
6628             case CMD_BLACKLIST_NETWORK:
6629                 s = "CMD_BLACKLIST_NETWORK";
6630                 break;
6631             case CMD_CLEAR_BLACKLIST:
6632                 s = "CMD_CLEAR_BLACKLIST";
6633                 break;
6634             case CMD_SAVE_CONFIG:
6635                 s = "CMD_SAVE_CONFIG";
6636                 break;
6637             case CMD_GET_CONFIGURED_NETWORKS:
6638                 s = "CMD_GET_CONFIGURED_NETWORKS";
6639                 break;
6640             case CMD_GET_SUPPORTED_FEATURES:
6641                 s = "CMD_GET_SUPPORTED_FEATURES";
6642                 break;
6643             case CMD_UNWANTED_NETWORK:
6644                 s = "CMD_UNWANTED_NETWORK";
6645                 break;
6646             case CMD_NETWORK_STATUS:
6647                 s = "CMD_NETWORK_STATUS";
6648                 break;
6649             case CMD_GET_LINK_LAYER_STATS:
6650                 s = "CMD_GET_LINK_LAYER_STATS";
6651                 break;
6652             case CMD_GET_MATCHING_CONFIG:
6653                 s = "CMD_GET_MATCHING_CONFIG";
6654                 break;
6655             case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
6656                 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS";
6657                 break;
6658             case CMD_DISCONNECT:
6659                 s = "CMD_DISCONNECT";
6660                 break;
6661             case CMD_RECONNECT:
6662                 s = "CMD_RECONNECT";
6663                 break;
6664             case CMD_REASSOCIATE:
6665                 s = "CMD_REASSOCIATE";
6666                 break;
6667             case CMD_GET_CONNECTION_STATISTICS:
6668                 s = "CMD_GET_CONNECTION_STATISTICS";
6669                 break;
6670             case CMD_SET_HIGH_PERF_MODE:
6671                 s = "CMD_SET_HIGH_PERF_MODE";
6672                 break;
6673             case CMD_SET_COUNTRY_CODE:
6674                 s = "CMD_SET_COUNTRY_CODE";
6675                 break;
6676             case CMD_ENABLE_RSSI_POLL:
6677                 s = "CMD_ENABLE_RSSI_POLL";
6678                 break;
6679             case CMD_RSSI_POLL:
6680                 s = "CMD_RSSI_POLL";
6681                 break;
6682             case CMD_START_PACKET_FILTERING:
6683                 s = "CMD_START_PACKET_FILTERING";
6684                 break;
6685             case CMD_STOP_PACKET_FILTERING:
6686                 s = "CMD_STOP_PACKET_FILTERING";
6687                 break;
6688             case CMD_SET_SUSPEND_OPT_ENABLED:
6689                 s = "CMD_SET_SUSPEND_OPT_ENABLED";
6690                 break;
6691             case CMD_NO_NETWORKS_PERIODIC_SCAN:
6692                 s = "CMD_NO_NETWORKS_PERIODIC_SCAN";
6693                 break;
6694             case CMD_UPDATE_LINKPROPERTIES:
6695                 s = "CMD_UPDATE_LINKPROPERTIES";
6696                 break;
6697             case CMD_RELOAD_TLS_AND_RECONNECT:
6698                 s = "CMD_RELOAD_TLS_AND_RECONNECT";
6699                 break;
6700             case WifiManager.CONNECT_NETWORK:
6701                 s = "CONNECT_NETWORK";
6702                 break;
6703             case WifiManager.SAVE_NETWORK:
6704                 s = "SAVE_NETWORK";
6705                 break;
6706             case WifiManager.FORGET_NETWORK:
6707                 s = "FORGET_NETWORK";
6708                 break;
6709             case WifiMonitor.SUP_CONNECTION_EVENT:
6710                 s = "SUP_CONNECTION_EVENT";
6711                 break;
6712             case WifiMonitor.SUP_DISCONNECTION_EVENT:
6713                 s = "SUP_DISCONNECTION_EVENT";
6714                 break;
6715             case WifiMonitor.SCAN_RESULTS_EVENT:
6716                 s = "SCAN_RESULTS_EVENT";
6717                 break;
6718             case WifiMonitor.SCAN_FAILED_EVENT:
6719                 s = "SCAN_FAILED_EVENT";
6720                 break;
6721             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6722                 s = "SUPPLICANT_STATE_CHANGE_EVENT";
6723                 break;
6724             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6725                 s = "AUTHENTICATION_FAILURE_EVENT";
6726                 break;
6727             case WifiMonitor.SSID_TEMP_DISABLED:
6728                 s = "SSID_TEMP_DISABLED";
6729                 break;
6730             case WifiMonitor.SSID_REENABLED:
6731                 s = "SSID_REENABLED";
6732                 break;
6733             case WifiMonitor.WPS_SUCCESS_EVENT:
6734                 s = "WPS_SUCCESS_EVENT";
6735                 break;
6736             case WifiMonitor.WPS_FAIL_EVENT:
6737                 s = "WPS_FAIL_EVENT";
6738                 break;
6739             case WifiMonitor.SUP_REQUEST_IDENTITY:
6740                 s = "SUP_REQUEST_IDENTITY";
6741                 break;
6742             case WifiMonitor.NETWORK_CONNECTION_EVENT:
6743                 s = "NETWORK_CONNECTION_EVENT";
6744                 break;
6745             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6746                 s = "NETWORK_DISCONNECTION_EVENT";
6747                 break;
6748             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6749                 s = "ASSOCIATION_REJECTION_EVENT";
6750                 break;
6751             case WifiMonitor.ANQP_DONE_EVENT:
6752                 s = "WifiMonitor.ANQP_DONE_EVENT";
6753                 break;
6754             case WifiMonitor.GAS_QUERY_DONE_EVENT:
6755                 s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
6756                 break;
6757             case WifiMonitor.HS20_DEAUTH_EVENT:
6758                 s = "WifiMonitor.HS20_DEAUTH_EVENT";
6759                 break;
6760             case WifiMonitor.GAS_QUERY_START_EVENT:
6761                 s = "WifiMonitor.GAS_QUERY_START_EVENT";
6762                 break;
6763             case CMD_SET_OPERATIONAL_MODE:
6764                 s = "CMD_SET_OPERATIONAL_MODE";
6765                 break;
6766             case CMD_START_SCAN:
6767                 s = "CMD_START_SCAN";
6768                 break;
6769             case CMD_DISABLE_P2P_RSP:
6770                 s = "CMD_DISABLE_P2P_RSP";
6771                 break;
6772             case CMD_DISABLE_P2P_REQ:
6773                 s = "CMD_DISABLE_P2P_REQ";
6774                 break;
6775             case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
6776                 s = "GOOD_LINK_DETECTED";
6777                 break;
6778             case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
6779                 s = "POOR_LINK_DETECTED";
6780                 break;
6781             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
6782                 s = "GROUP_CREATING_TIMED_OUT";
6783                 break;
6784             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
6785                 s = "P2P_CONNECTION_CHANGED";
6786                 break;
6787             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
6788                 s = "P2P.DISCONNECT_WIFI_RESPONSE";
6789                 break;
6790             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
6791                 s = "P2P.SET_MIRACAST_MODE";
6792                 break;
6793             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
6794                 s = "P2P.BLOCK_DISCOVERY";
6795                 break;
6796             case WifiP2pServiceImpl.SET_COUNTRY_CODE:
6797                 s = "P2P.SET_COUNTRY_CODE";
6798                 break;
6799             case WifiManager.CANCEL_WPS:
6800                 s = "CANCEL_WPS";
6801                 break;
6802             case WifiManager.CANCEL_WPS_FAILED:
6803                 s = "CANCEL_WPS_FAILED";
6804                 break;
6805             case WifiManager.CANCEL_WPS_SUCCEDED:
6806                 s = "CANCEL_WPS_SUCCEDED";
6807                 break;
6808             case WifiManager.START_WPS:
6809                 s = "START_WPS";
6810                 break;
6811             case WifiManager.START_WPS_SUCCEEDED:
6812                 s = "START_WPS_SUCCEEDED";
6813                 break;
6814             case WifiManager.WPS_FAILED:
6815                 s = "WPS_FAILED";
6816                 break;
6817             case WifiManager.WPS_COMPLETED:
6818                 s = "WPS_COMPLETED";
6819                 break;
6820             case WifiManager.RSSI_PKTCNT_FETCH:
6821                 s = "RSSI_PKTCNT_FETCH";
6822                 break;
6823             case CMD_IP_CONFIGURATION_LOST:
6824                 s = "CMD_IP_CONFIGURATION_LOST";
6825                 break;
6826             case CMD_IP_CONFIGURATION_SUCCESSFUL:
6827                 s = "CMD_IP_CONFIGURATION_SUCCESSFUL";
6828                 break;
6829             case CMD_IP_REACHABILITY_LOST:
6830                 s = "CMD_IP_REACHABILITY_LOST";
6831                 break;
6832             case CMD_STATIC_IP_SUCCESS:
6833                 s = "CMD_STATIC_IP_SUCCESSFUL";
6834                 break;
6835             case CMD_STATIC_IP_FAILURE:
6836                 s = "CMD_STATIC_IP_FAILURE";
6837                 break;
6838             case DhcpStateMachine.DHCP_SUCCESS:
6839                 s = "DHCP_SUCCESS";
6840                 break;
6841             case DhcpStateMachine.DHCP_FAILURE:
6842                 s = "DHCP_FAILURE";
6843                 break;
6844             case CMD_TARGET_BSSID:
6845                 s = "CMD_TARGET_BSSID";
6846                 break;
6847             case CMD_ASSOCIATED_BSSID:
6848                 s = "CMD_ASSOCIATED_BSSID";
6849                 break;
6850             case CMD_REMOVE_APP_CONFIGURATIONS:
6851                 s = "CMD_REMOVE_APP_CONFIGURATIONS";
6852                 break;
6853             case CMD_REMOVE_USER_CONFIGURATIONS:
6854                 s = "CMD_REMOVE_USER_CONFIGURATIONS";
6855                 break;
6856             case CMD_ROAM_WATCHDOG_TIMER:
6857                 s = "CMD_ROAM_WATCHDOG_TIMER";
6858                 break;
6859             case CMD_SCREEN_STATE_CHANGED:
6860                 s = "CMD_SCREEN_STATE_CHANGED";
6861                 break;
6862             case CMD_DISCONNECTING_WATCHDOG_TIMER:
6863                 s = "CMD_DISCONNECTING_WATCHDOG_TIMER";
6864                 break;
6865             case CMD_RESTART_AUTOJOIN_OFFLOAD:
6866                 s = "CMD_RESTART_AUTOJOIN_OFFLOAD";
6867                 break;
6868             case CMD_STARTED_PNO_DBG:
6869                 s = "CMD_STARTED_PNO_DBG";
6870                 break;
6871             case CMD_STARTED_GSCAN_DBG:
6872                 s = "CMD_STARTED_GSCAN_DBG";
6873                 break;
6874             case CMD_PNO_NETWORK_FOUND:
6875                 s = "CMD_PNO_NETWORK_FOUND";
6876                 break;
6877             case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
6878                 s = "CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION";
6879                 break;
6880             default:
6881                 s = "what:" + Integer.toString(what);
6882                 break;
6883         }
6884         return s;
6885     }
6886 
registerConnected()6887     void registerConnected() {
6888        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6889            long now_ms = System.currentTimeMillis();
6890            // We are switching away from this configuration,
6891            // hence record the time we were connected last
6892            WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
6893            if (config != null) {
6894                config.lastConnected = System.currentTimeMillis();
6895                config.autoJoinBailedDueToLowRssi = false;
6896                config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
6897                config.numConnectionFailures = 0;
6898                config.numIpConfigFailures = 0;
6899                config.numAuthFailures = 0;
6900                config.numAssociation++;
6901            }
6902            mBadLinkspeedcount = 0;
6903        }
6904     }
6905 
registerDisconnected()6906     void registerDisconnected() {
6907         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6908             long now_ms = System.currentTimeMillis();
6909             // We are switching away from this configuration,
6910             // hence record the time we were connected last
6911             WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
6912             if (config != null) {
6913                 config.lastDisconnected = System.currentTimeMillis();
6914                 if (config.ephemeral) {
6915                     // Remove ephemeral WifiConfigurations from file
6916                     mWifiConfigStore.forgetNetwork(mLastNetworkId);
6917                 }
6918             }
6919         }
6920     }
6921 
noteWifiDisabledWhileAssociated()6922     void noteWifiDisabledWhileAssociated() {
6923         // We got disabled by user while we were associated, make note of it
6924         int rssi = mWifiInfo.getRssi();
6925         WifiConfiguration config = getCurrentWifiConfiguration();
6926         if (getCurrentState() == mConnectedState
6927                 && rssi != WifiInfo.INVALID_RSSI
6928                 && config != null) {
6929             boolean is24GHz = mWifiInfo.is24GHz();
6930             boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get())
6931                     || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get());
6932             boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get())
6933                     || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get());
6934             boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get())
6935                     || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get());
6936             if (isBadRSSI) {
6937                 // Take note that we got disabled while RSSI was Bad
6938                 config.numUserTriggeredWifiDisableLowRSSI++;
6939             } else if (isLowRSSI) {
6940                 // Take note that we got disabled while RSSI was Low
6941                 config.numUserTriggeredWifiDisableBadRSSI++;
6942             } else if (!isHighRSSI) {
6943                 // Take note that we got disabled while RSSI was Not high
6944                 config.numUserTriggeredWifiDisableNotHighRSSI++;
6945             }
6946         }
6947     }
6948 
getCurrentWifiConfiguration()6949     WifiConfiguration getCurrentWifiConfiguration() {
6950         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
6951             return null;
6952         }
6953         return mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
6954     }
6955 
getCurrentScanResult()6956     ScanResult getCurrentScanResult() {
6957         WifiConfiguration config = getCurrentWifiConfiguration();
6958         if (config == null) {
6959             return null;
6960         }
6961         String BSSID = mWifiInfo.getBSSID();
6962         if (BSSID == null) {
6963             BSSID = mTargetRoamBSSID;
6964         }
6965         ScanDetailCache scanDetailCache =
6966                 mWifiConfigStore.getScanDetailCache(config);
6967 
6968         if (scanDetailCache == null) {
6969             return null;
6970         }
6971 
6972         return scanDetailCache.get(BSSID);
6973     }
6974 
getCurrentBSSID()6975     String getCurrentBSSID() {
6976         if (linkDebouncing) {
6977             return null;
6978         }
6979         return mLastBssid;
6980     }
6981 
6982     class ConnectModeState extends State {
6983 
6984         @Override
enter()6985         public void enter() {
6986             connectScanningService();
6987         }
6988 
6989         @Override
processMessage(Message message)6990         public boolean processMessage(Message message) {
6991             WifiConfiguration config;
6992             int netId;
6993             boolean ok;
6994             boolean didDisconnect;
6995             String bssid;
6996             String ssid;
6997             NetworkUpdateResult result;
6998             logStateAndMessage(message, getClass().getSimpleName());
6999 
7000             switch (message.what) {
7001                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
7002                     mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
7003                     didBlackListBSSID = false;
7004                     bssid = (String) message.obj;
7005                     if (bssid == null || TextUtils.isEmpty(bssid)) {
7006                         // If BSSID is null, use the target roam BSSID
7007                         bssid = mTargetRoamBSSID;
7008                     }
7009                     if (bssid != null) {
7010                         // If we have a BSSID, tell configStore to black list it
7011                         synchronized(mScanResultCache) {
7012                             didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList
7013                                     (mLastNetworkId, bssid, false);
7014                         }
7015                     }
7016                     mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
7017                     break;
7018                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
7019                     mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
7020                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
7021                     break;
7022                 case WifiMonitor.SSID_TEMP_DISABLED:
7023                 case WifiMonitor.SSID_REENABLED:
7024                     String substr = (String) message.obj;
7025                     String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ?
7026                             "temp-disabled" : "re-enabled";
7027                     logd("ConnectModeState SSID state=" + en + " nid="
7028                             + Integer.toString(message.arg1) + " [" + substr + "]");
7029                     synchronized(mScanResultCache) {
7030                         mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what ==
7031                                 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID());
7032                     }
7033                     break;
7034                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
7035                     SupplicantState state = handleSupplicantStateChange(message);
7036                     // A driver/firmware hang can now put the interface in a down state.
7037                     // We detect the interface going down and recover from it
7038                     if (!SupplicantState.isDriverActive(state)) {
7039                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
7040                             handleNetworkDisconnect();
7041                         }
7042                         log("Detected an interface down, restart driver");
7043                         transitionTo(mDriverStoppedState);
7044                         sendMessage(CMD_START_DRIVER);
7045                         break;
7046                     }
7047 
7048                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
7049                     // when authentication times out after a successful connection,
7050                     // we can figure this from the supplicant state. If supplicant
7051                     // state is DISCONNECTED, but the mNetworkInfo says we are not
7052                     // disconnected, we need to handle a disconnection
7053                     if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
7054                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
7055                         if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
7056                         handleNetworkDisconnect();
7057                         transitionTo(mDisconnectedState);
7058                     }
7059 
7060                     // If we have COMPLETED a connection to a BSSID, start doing
7061                     // DNAv4/DNAv6 -style probing for on-link neighbors of
7062                     // interest (e.g. routers); harmless if none are configured.
7063                     if (state == SupplicantState.COMPLETED) {
7064                         if (mIpReachabilityMonitor != null) {
7065                             mIpReachabilityMonitor.probeAll();
7066                         }
7067                     }
7068                     break;
7069                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
7070                     if (message.arg1 == 1) {
7071                         mWifiNative.disconnect();
7072                         mTemporarilyDisconnectWifi = true;
7073                     } else {
7074                         mWifiNative.reconnect();
7075                         mTemporarilyDisconnectWifi = false;
7076                     }
7077                     break;
7078                 case CMD_ADD_OR_UPDATE_NETWORK:
7079                     config = (WifiConfiguration) message.obj;
7080 
7081                     if (!recordUidIfAuthorized(config, message.sendingUid,
7082                             /* onlyAnnotate */ false)) {
7083                         logw("Not authorized to update network "
7084                              + " config=" + config.SSID
7085                              + " cnid=" + config.networkId
7086                              + " uid=" + message.sendingUid);
7087                         replyToMessage(message, message.what, FAILURE);
7088                         break;
7089                     }
7090 
7091                     int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid);
7092                     if (res < 0) {
7093                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7094                     } else {
7095                         WifiConfiguration curConfig = getCurrentWifiConfiguration();
7096                         if (curConfig != null && config != null) {
7097                             if (curConfig.priority < config.priority
7098                                     && config.status == WifiConfiguration.Status.ENABLED) {
7099                                 // Interpret this as a connect attempt
7100                                 // Set the last selected configuration so as to allow the system to
7101                                 // stick the last user choice without persisting the choice
7102                                 mWifiConfigStore.setLastSelectedConfiguration(res);
7103                                 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
7104                                 mWifiConfigStore.writeKnownNetworkHistory(false);
7105 
7106                                 // Remember time of last connection attempt
7107                                 lastConnectAttemptTimestamp = System.currentTimeMillis();
7108 
7109                                 mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7110 
7111                                 // As a courtesy to the caller, trigger a scan now
7112                                 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null);
7113                             }
7114                         }
7115                     }
7116                     replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
7117                     break;
7118                 case CMD_REMOVE_NETWORK:
7119                     netId = message.arg1;
7120                     if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
7121                             /* onlyAnnotate */ false)) {
7122                         logw("Not authorized to remove network "
7123                              + " cnid=" + netId
7124                              + " uid=" + message.sendingUid);
7125                         replyToMessage(message, message.what, FAILURE);
7126                         break;
7127                     }
7128 
7129                     ok = mWifiConfigStore.removeNetwork(message.arg1);
7130                     if (!ok) {
7131                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7132                     }
7133                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
7134                     break;
7135                 case CMD_ENABLE_NETWORK:
7136                     boolean disableOthers = message.arg2 == 1;
7137                     netId = message.arg1;
7138                     config = mWifiConfigStore.getWifiConfiguration(netId);
7139                     if (config == null) {
7140                         loge("No network with id = " + netId);
7141                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7142                         break;
7143                     }
7144 
7145                     // Tell autojoin the user did try to select to that network
7146                     // However, do NOT persist the choice by bumping the priority of the network
7147                     if (disableOthers) {
7148                         mWifiAutoJoinController.
7149                                 updateConfigurationHistory(netId, true, false);
7150                         // Set the last selected configuration so as to allow the system to
7151                         // stick the last user choice without persisting the choice
7152                         mWifiConfigStore.setLastSelectedConfiguration(netId);
7153 
7154                         // Remember time of last connection attempt
7155                         lastConnectAttemptTimestamp = System.currentTimeMillis();
7156 
7157                         mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7158                     }
7159                     // Cancel auto roam requests
7160                     autoRoamSetBSSID(netId, "any");
7161 
7162                     int uid = message.sendingUid;
7163                     ok = mWifiConfigStore.enableNetwork(netId, disableOthers, uid);
7164                     if (!ok) {
7165                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7166                     }
7167 
7168                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
7169                     break;
7170                 case CMD_ENABLE_ALL_NETWORKS:
7171                     long time = android.os.SystemClock.elapsedRealtime();
7172                     if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
7173                         mWifiConfigStore.enableAllNetworks();
7174                         mLastEnableAllNetworksTime = time;
7175                     }
7176                     break;
7177                 case WifiManager.DISABLE_NETWORK:
7178                     if (mWifiConfigStore.disableNetwork(message.arg1,
7179                             WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) {
7180                         replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
7181                     } else {
7182                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7183                         replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
7184                                 WifiManager.ERROR);
7185                     }
7186                     break;
7187                 case CMD_DISABLE_EPHEMERAL_NETWORK:
7188                     config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj);
7189                     if (config != null) {
7190                         if (config.networkId == mLastNetworkId) {
7191                             // Disconnect and let autojoin reselect a new network
7192                             sendMessage(CMD_DISCONNECT);
7193                         }
7194                     }
7195                     break;
7196                 case CMD_BLACKLIST_NETWORK:
7197                     mWifiConfigStore.blackListBssid((String) message.obj);
7198                     break;
7199                 case CMD_CLEAR_BLACKLIST:
7200                     mWifiConfigStore.clearBssidBlacklist();
7201                     break;
7202                 case CMD_SAVE_CONFIG:
7203                     ok = mWifiConfigStore.saveConfig();
7204 
7205                     if (DBG) logd("did save config " + ok);
7206                     replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
7207 
7208                     // Inform the backup manager about a data change
7209                     IBackupManager ibm = IBackupManager.Stub.asInterface(
7210                             ServiceManager.getService(Context.BACKUP_SERVICE));
7211                     if (ibm != null) {
7212                         try {
7213                             ibm.dataChanged("com.android.providers.settings");
7214                         } catch (Exception e) {
7215                             // Try again later
7216                         }
7217                     }
7218                     break;
7219                 case CMD_GET_CONFIGURED_NETWORKS:
7220                     replyToMessage(message, message.what,
7221                             mWifiConfigStore.getConfiguredNetworks());
7222                     break;
7223                 case WifiMonitor.SUP_REQUEST_IDENTITY:
7224                     int networkId = message.arg2;
7225                     boolean identitySent = false;
7226                     int eapMethod = WifiEnterpriseConfig.Eap.NONE;
7227 
7228                     if (targetWificonfiguration != null
7229                             && targetWificonfiguration.enterpriseConfig != null) {
7230                         eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
7231                     }
7232 
7233                     // For SIM & AKA/AKA' EAP method Only, get identity from ICC
7234                     if (targetWificonfiguration != null
7235                             && targetWificonfiguration.networkId == networkId
7236                             && targetWificonfiguration.allowedKeyManagement
7237                                     .get(WifiConfiguration.KeyMgmt.IEEE8021X)
7238                             &&  (eapMethod == WifiEnterpriseConfig.Eap.SIM
7239                             || eapMethod == WifiEnterpriseConfig.Eap.AKA
7240                             || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
7241                         TelephonyManager tm = (TelephonyManager)
7242                                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
7243                         if (tm != null) {
7244                             String imsi = tm.getSubscriberId();
7245                             String mccMnc = "";
7246 
7247                             if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
7248                                  mccMnc = tm.getSimOperator();
7249 
7250                             String identity = buildIdentity(eapMethod, imsi, mccMnc);
7251 
7252                             if (!identity.isEmpty()) {
7253                                 mWifiNative.simIdentityResponse(networkId, identity);
7254                                 identitySent = true;
7255                             }
7256                         }
7257                     }
7258                     if (!identitySent) {
7259                         // Supplicant lacks credentials to connect to that network, hence black list
7260                         ssid = (String) message.obj;
7261                         if (targetWificonfiguration != null && ssid != null
7262                                 && targetWificonfiguration.SSID != null
7263                                 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
7264                             mWifiConfigStore.handleSSIDStateChange(
7265                                     targetWificonfiguration.networkId, false,
7266                                     "AUTH_FAILED no identity", null);
7267                         }
7268                         // Disconnect now, as we don't have any way to fullfill
7269                         // the  supplicant request.
7270                         mWifiConfigStore.setLastSelectedConfiguration(
7271                                 WifiConfiguration.INVALID_NETWORK_ID);
7272                         mWifiNative.disconnect();
7273                     }
7274                     break;
7275                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
7276                     logd("Received SUP_REQUEST_SIM_AUTH");
7277                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
7278                     if (requestData != null) {
7279                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
7280                             handleGsmAuthRequest(requestData);
7281                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
7282                             || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
7283                             handle3GAuthRequest(requestData);
7284                         }
7285                     } else {
7286                         loge("Invalid sim auth request");
7287                     }
7288                     break;
7289                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
7290                     replyToMessage(message, message.what,
7291                             mWifiConfigStore.getPrivilegedConfiguredNetworks());
7292                     break;
7293                 case CMD_GET_MATCHING_CONFIG:
7294                     replyToMessage(message, message.what,
7295                             mWifiConfigStore.getMatchingConfig((ScanResult)message.obj));
7296                     break;
7297                 /* Do a redundant disconnect without transition */
7298                 case CMD_DISCONNECT:
7299                     mWifiConfigStore.setLastSelectedConfiguration
7300                             (WifiConfiguration.INVALID_NETWORK_ID);
7301                     mWifiNative.disconnect();
7302                     break;
7303                 case CMD_RECONNECT:
7304                     mWifiAutoJoinController.attemptAutoJoin();
7305                     break;
7306                 case CMD_REASSOCIATE:
7307                     lastConnectAttemptTimestamp = System.currentTimeMillis();
7308                     mWifiNative.reassociate();
7309                     break;
7310                 case CMD_RELOAD_TLS_AND_RECONNECT:
7311                     if (mWifiConfigStore.needsUnlockedKeyStore()) {
7312                         logd("Reconnecting to give a chance to un-connected TLS networks");
7313                         mWifiNative.disconnect();
7314                         lastConnectAttemptTimestamp = System.currentTimeMillis();
7315                         mWifiNative.reconnect();
7316                     }
7317                     break;
7318                 case CMD_AUTO_ROAM:
7319                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7320                     return HANDLED;
7321                 case CMD_AUTO_CONNECT:
7322                     /* Work Around: wpa_supplicant can get in a bad state where it returns a non
7323                      * associated status to the STATUS command but somehow-someplace still thinks
7324                      * it is associated and thus will ignore select/reconnect command with
7325                      * following message:
7326                      * "Already associated with the selected network - do nothing"
7327                      *
7328                      * Hence, sends a disconnect to supplicant first.
7329                      */
7330                     didDisconnect = false;
7331                     if (getCurrentState() != mDisconnectedState) {
7332                         /** Supplicant will ignore the reconnect if we are currently associated,
7333                          * hence trigger a disconnect
7334                          */
7335                         didDisconnect = true;
7336                         mWifiNative.disconnect();
7337                     }
7338 
7339                     /* connect command coming from auto-join */
7340                     config = (WifiConfiguration) message.obj;
7341                     netId = message.arg1;
7342                     int roam = message.arg2;
7343                     logd("CMD_AUTO_CONNECT sup state "
7344                             + mSupplicantStateTracker.getSupplicantStateName()
7345                             + " my state " + getCurrentState().getName()
7346                             + " nid=" + Integer.toString(netId)
7347                             + " roam=" + Integer.toString(roam));
7348                     if (config == null) {
7349                         loge("AUTO_CONNECT and no config, bail out...");
7350                         break;
7351                     }
7352 
7353                     /* Make sure we cancel any previous roam request */
7354                     autoRoamSetBSSID(netId, config.BSSID);
7355 
7356                     /* Save the network config */
7357                     logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
7358                             + " nid=" + Integer.toString(netId));
7359                     result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
7360                     netId = result.getNetworkId();
7361                     logd("CMD_AUTO_CONNECT did save config -> "
7362                             + " nid=" + Integer.toString(netId));
7363 
7364                     // Since we updated the config,read it back from config store:
7365                     config = mWifiConfigStore.getWifiConfiguration(netId);
7366                     if (config == null) {
7367                         loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
7368                         break;
7369                     }
7370                     if (netId != config.networkId) {
7371                         loge("CMD_AUTO_CONNECT couldn't update the config, want"
7372                                 + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
7373                         break;
7374                     }
7375 
7376                     if (deferForUserInput(message, netId, false)) {
7377                         break;
7378                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
7379                                                                    WifiConfiguration.USER_BANNED) {
7380                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7381                                 WifiManager.NOT_AUTHORIZED);
7382                         break;
7383                     }
7384 
7385                     // Make sure the network is enabled, since supplicant will not reenable it
7386                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
7387 
7388                     // If we're autojoining a network that the user or an app explicitly selected,
7389                     // keep track of the UID that selected it.
7390                     int lastConnectUid = mWifiConfigStore.isLastSelectedConfiguration(config) ?
7391                             config.lastConnectUid : WifiConfiguration.UNKNOWN_UID;
7392 
7393                     if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false,
7394                             lastConnectUid) && mWifiNative.reconnect()) {
7395                         lastConnectAttemptTimestamp = System.currentTimeMillis();
7396                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
7397                         config = mWifiConfigStore.getWifiConfiguration(netId);
7398                         if (config != null
7399                                 && !mWifiConfigStore.isLastSelectedConfiguration(config)) {
7400                             // If we autojoined a different config than the user selected one,
7401                             // it means we could not see the last user selection,
7402                             // or that the last user selection was faulty and ended up blacklisted
7403                             // for some reason (in which case the user is notified with an error
7404                             // message in the Wifi picker), and thus we managed to auto-join away
7405                             // from the selected  config. -> in that case we need to forget
7406                             // the selection because we don't want to abruptly switch back to it.
7407                             //
7408                             // Note that the user selection is also forgotten after a period of time
7409                             // during which the device has been disconnected.
7410                             // The default value is 30 minutes : see the code path at bottom of
7411                             // setScanResults() function.
7412                             mWifiConfigStore.
7413                                  setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
7414                         }
7415                         mAutoRoaming = roam;
7416                         if (isRoaming() || linkDebouncing) {
7417                             transitionTo(mRoamingState);
7418                         } else if (didDisconnect) {
7419                             transitionTo(mDisconnectingState);
7420                         } else {
7421                             /* Already in disconnected state, nothing to change */
7422                             if (!mScreenOn && mLegacyPnoEnabled && mBackgroundScanSupported) {
7423                                 int delay = 60 * 1000;
7424                                 if (VDBG) {
7425                                     logd("Starting PNO alarm: " + delay);
7426                                 }
7427                                 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
7428                                        System.currentTimeMillis() + delay,
7429                                        mPnoIntent);
7430                             }
7431                             mRestartAutoJoinOffloadCounter++;
7432                         }
7433                     } else {
7434                         loge("Failed to connect config: " + config + " netId: " + netId);
7435                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7436                                 WifiManager.ERROR);
7437                         break;
7438                     }
7439                     break;
7440                 case CMD_REMOVE_APP_CONFIGURATIONS:
7441                     mWifiConfigStore.removeNetworksForApp((ApplicationInfo) message.obj);
7442                     break;
7443                 case CMD_REMOVE_USER_CONFIGURATIONS:
7444                     mWifiConfigStore.removeNetworksForUser(message.arg1);
7445                     break;
7446                 case WifiManager.CONNECT_NETWORK:
7447                     /**
7448                      *  The connect message can contain a network id passed as arg1 on message or
7449                      * or a config passed as obj on message.
7450                      * For a new network, a config is passed to create and connect.
7451                      * For an existing network, a network id is passed
7452                      */
7453                     netId = message.arg1;
7454                     config = (WifiConfiguration) message.obj;
7455                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7456                     boolean updatedExisting = false;
7457 
7458                     /* Save the network config */
7459                     if (config != null) {
7460                         // When connecting to an access point, WifiStateMachine wants to update the
7461                         // relevant config with administrative data. This update should not be
7462                         // considered a 'real' update, therefore lockdown by Device Owner must be
7463                         // disregarded.
7464                         if (!recordUidIfAuthorized(config, message.sendingUid,
7465                                 /* onlyAnnotate */ true)) {
7466                             logw("Not authorized to update network "
7467                                  + " config=" + config.SSID
7468                                  + " cnid=" + config.networkId
7469                                  + " uid=" + message.sendingUid);
7470                             replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7471                                            WifiManager.NOT_AUTHORIZED);
7472                             break;
7473                         }
7474 
7475                         String configKey = config.configKey(true /* allowCached */);
7476                         WifiConfiguration savedConfig =
7477                                 mWifiConfigStore.getWifiConfiguration(configKey);
7478                         if (savedConfig != null) {
7479                             // There is an existing config with this netId, but it wasn't exposed
7480                             // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore#
7481                             // getConfiguredNetworks). Remove those bits and update the config.
7482                             config = savedConfig;
7483                             logd("CONNECT_NETWORK updating existing config with id=" +
7484                                     config.networkId + " configKey=" + configKey);
7485                             config.ephemeral = false;
7486                             config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED;
7487                             updatedExisting = true;
7488                         }
7489 
7490                         result = mWifiConfigStore.saveNetwork(config, message.sendingUid);
7491                         netId = result.getNetworkId();
7492                     }
7493                     config = mWifiConfigStore.getWifiConfiguration(netId);
7494 
7495                     if (config == null) {
7496                         logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
7497                                 + mSupplicantStateTracker.getSupplicantStateName() + " my state "
7498                                 + getCurrentState().getName());
7499                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7500                                 WifiManager.ERROR);
7501                         break;
7502                     } else {
7503                         String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : "";
7504                         logd("CONNECT_NETWORK id=" + Integer.toString(netId)
7505                                 + " config=" + config.SSID
7506                                 + " cnid=" + config.networkId
7507                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
7508                                 + " my state " + getCurrentState().getName()
7509                                 + " uid = " + message.sendingUid
7510                                 + wasSkipped);
7511                     }
7512 
7513                     autoRoamSetBSSID(netId, "any");
7514 
7515                     if (message.sendingUid == Process.WIFI_UID
7516                         || message.sendingUid == Process.SYSTEM_UID) {
7517                         // As a sanity measure, clear the BSSID in the supplicant network block.
7518                         // If system or Wifi Settings want to connect, they will not
7519                         // specify the BSSID.
7520                         // If an app however had added a BSSID to this configuration, and the BSSID
7521                         // was wrong, Then we would forever fail to connect until that BSSID
7522                         // is cleaned up.
7523                         clearConfigBSSID(config, "CONNECT_NETWORK");
7524                     }
7525 
7526                     if (deferForUserInput(message, netId, true)) {
7527                         break;
7528                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
7529                                                                     WifiConfiguration.USER_BANNED) {
7530                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7531                                 WifiManager.NOT_AUTHORIZED);
7532                         break;
7533                     }
7534 
7535                     mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
7536 
7537                     /* Tell autojoin the user did try to connect to that network if from settings */
7538                     boolean persist =
7539                         mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
7540                     mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist);
7541 
7542                     mWifiConfigStore.setLastSelectedConfiguration(netId);
7543 
7544                     didDisconnect = false;
7545                     if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
7546                             && mLastNetworkId != netId) {
7547                         /** Supplicant will ignore the reconnect if we are currently associated,
7548                          * hence trigger a disconnect
7549                          */
7550                         didDisconnect = true;
7551                         mWifiNative.disconnect();
7552                     }
7553 
7554                     // Make sure the network is enabled, since supplicant will not reenable it
7555                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
7556 
7557                     if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true,
7558                             message.sendingUid) && mWifiNative.reconnect()) {
7559                         lastConnectAttemptTimestamp = System.currentTimeMillis();
7560                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
7561 
7562                         /* The state tracker handles enabling networks upon completion/failure */
7563                         mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
7564                         replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
7565                         if (didDisconnect) {
7566                             /* Expect a disconnection from the old connection */
7567                             transitionTo(mDisconnectingState);
7568                         } else if (updatedExisting && getCurrentState() == mConnectedState &&
7569                                 getCurrentWifiConfiguration().networkId == netId) {
7570                             // Update the current set of network capabilities, but stay in the
7571                             // current state.
7572                             updateCapabilities(config);
7573                         } else {
7574                             /**
7575                              *  Directly go to disconnected state where we
7576                              * process the connection events from supplicant
7577                              **/
7578                             transitionTo(mDisconnectedState);
7579                         }
7580                     } else {
7581                         loge("Failed to connect config: " + config + " netId: " + netId);
7582                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7583                                 WifiManager.ERROR);
7584                         break;
7585                     }
7586                     break;
7587                 case WifiManager.SAVE_NETWORK:
7588                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7589                     // Fall thru
7590                 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
7591                     lastSavedConfigurationAttempt = null; // Used for debug
7592                     config = (WifiConfiguration) message.obj;
7593                     if (config == null) {
7594                         loge("ERROR: SAVE_NETWORK with null configuration"
7595                                 + mSupplicantStateTracker.getSupplicantStateName()
7596                                 + " my state " + getCurrentState().getName());
7597                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7598                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7599                                 WifiManager.ERROR);
7600                         break;
7601                     }
7602                     lastSavedConfigurationAttempt = new WifiConfiguration(config);
7603                     int nid = config.networkId;
7604                     logd("SAVE_NETWORK id=" + Integer.toString(nid)
7605                                 + " config=" + config.SSID
7606                                 + " nid=" + config.networkId
7607                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
7608                                 + " my state " + getCurrentState().getName());
7609 
7610                     // Only record the uid if this is user initiated
7611                     boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
7612                     if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
7613                             /* onlyAnnotate */ false)) {
7614                         logw("Not authorized to update network "
7615                              + " config=" + config.SSID
7616                              + " cnid=" + config.networkId
7617                              + " uid=" + message.sendingUid);
7618                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7619                                        WifiManager.NOT_AUTHORIZED);
7620                         break;
7621                     }
7622 
7623                     result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
7624                     if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
7625                         if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
7626                             if (result.hasIpChanged()) {
7627                                 // The currently connection configuration was changed
7628                                 // We switched from DHCP to static or from static to DHCP, or the
7629                                 // static IP address has changed.
7630                                 log("Reconfiguring IP on connection");
7631                                 // TODO: clear addresses and disable IPv6
7632                                 // to simplify obtainingIpState.
7633                                 transitionTo(mObtainingIpState);
7634                             }
7635                             if (result.hasProxyChanged()) {
7636                                 log("Reconfiguring proxy on connection");
7637                                 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
7638                             }
7639                         }
7640                         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
7641                         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
7642 
7643                         if (VDBG) {
7644                            logd("Success save network nid="
7645                                     + Integer.toString(result.getNetworkId()));
7646                         }
7647 
7648                         synchronized(mScanResultCache) {
7649                             /**
7650                              * If the command comes from WifiManager, then
7651                              * tell autojoin the user did try to modify and save that network,
7652                              * and interpret the SAVE_NETWORK as a request to connect
7653                              */
7654                             boolean user = message.what == WifiManager.SAVE_NETWORK;
7655 
7656                             // Did this connect come from settings
7657                             boolean persistConnect =
7658                                 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
7659 
7660                             if (user) {
7661                                 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
7662                                 mWifiConfigStore.writeKnownNetworkHistory(false);
7663                             }
7664 
7665                             mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId()
7666                                     , user, persistConnect);
7667                             mWifiAutoJoinController.attemptAutoJoin();
7668                         }
7669                     } else {
7670                         loge("Failed to save network");
7671                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7672                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7673                                 WifiManager.ERROR);
7674                     }
7675                     break;
7676                 case WifiManager.FORGET_NETWORK:
7677                     // Debug only, remember last configuration that was forgotten
7678                     WifiConfiguration toRemove
7679                             = mWifiConfigStore.getWifiConfiguration(message.arg1);
7680                     if (toRemove == null) {
7681                         lastForgetConfigurationAttempt = null;
7682                     } else {
7683                         lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
7684                     }
7685                     // check that the caller owns this network
7686                     netId = message.arg1;
7687 
7688                     if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
7689                             /* onlyAnnotate */ false)) {
7690                         logw("Not authorized to forget network "
7691                              + " cnid=" + netId
7692                              + " uid=" + message.sendingUid);
7693                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7694                                 WifiManager.NOT_AUTHORIZED);
7695                         break;
7696                     }
7697 
7698                     if (mWifiConfigStore.forgetNetwork(message.arg1)) {
7699                         replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
7700                         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
7701                                 (WifiConfiguration) message.obj);
7702                     } else {
7703                         loge("Failed to forget network");
7704                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7705                                 WifiManager.ERROR);
7706                     }
7707                     break;
7708                 case WifiManager.START_WPS:
7709                     WpsInfo wpsInfo = (WpsInfo) message.obj;
7710                     WpsResult wpsResult;
7711                     switch (wpsInfo.setup) {
7712                         case WpsInfo.PBC:
7713                             wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
7714                             break;
7715                         case WpsInfo.KEYPAD:
7716                             wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
7717                             break;
7718                         case WpsInfo.DISPLAY:
7719                             wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
7720                             break;
7721                         default:
7722                             wpsResult = new WpsResult(Status.FAILURE);
7723                             loge("Invalid setup for WPS");
7724                             break;
7725                     }
7726                     mWifiConfigStore.setLastSelectedConfiguration
7727                             (WifiConfiguration.INVALID_NETWORK_ID);
7728                     if (wpsResult.status == Status.SUCCESS) {
7729                         replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
7730                         transitionTo(mWpsRunningState);
7731                     } else {
7732                         loge("Failed to start WPS with config " + wpsInfo.toString());
7733                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
7734                     }
7735                     break;
7736                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
7737                     if (DBG) log("Network connection established");
7738                     mLastNetworkId = message.arg1;
7739                     mLastBssid = (String) message.obj;
7740 
7741                     mWifiInfo.setBSSID(mLastBssid);
7742                     mWifiInfo.setNetworkId(mLastNetworkId);
7743 
7744                     sendNetworkStateChangeBroadcast(mLastBssid);
7745                     transitionTo(mObtainingIpState);
7746                     break;
7747                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7748                     // Calling handleNetworkDisconnect here is redundant because we might already
7749                     // have called it when leaving L2ConnectedState to go to disconnecting state
7750                     // or thru other path
7751                     // We should normally check the mWifiInfo or mLastNetworkId so as to check
7752                     // if they are valid, and only in this case call handleNEtworkDisconnect,
7753                     // TODO: this should be fixed for a L MR release
7754                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of
7755                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
7756                     // at the chip etc...
7757                     if (DBG) log("ConnectModeState: Network connection lost ");
7758                     handleNetworkDisconnect();
7759                     transitionTo(mDisconnectedState);
7760                     break;
7761                 case CMD_PNO_NETWORK_FOUND:
7762                     processPnoNetworkFound((ScanResult[])message.obj);
7763                     break;
7764                 default:
7765                     return NOT_HANDLED;
7766             }
7767             return HANDLED;
7768         }
7769     }
7770 
updateCapabilities(WifiConfiguration config)7771     private void updateCapabilities(WifiConfiguration config) {
7772         if (config.ephemeral) {
7773             mNetworkCapabilities.removeCapability(
7774                     NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7775         } else {
7776             mNetworkCapabilities.addCapability(
7777                     NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7778         }
7779         mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
7780     }
7781 
7782     private class WifiNetworkAgent extends NetworkAgent {
WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score)7783         public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
7784                 NetworkCapabilities nc, LinkProperties lp, int score) {
7785             super(l, c, TAG, ni, nc, lp, score);
7786         }
unwanted()7787         protected void unwanted() {
7788             // Ignore if we're not the current networkAgent.
7789             if (this != mNetworkAgent) return;
7790             if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
7791                     + Integer.toString(mWifiInfo.score));
7792             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
7793         }
7794 
7795         @Override
networkStatus(int status)7796         protected void networkStatus(int status) {
7797             if (this != mNetworkAgent) return;
7798             if (status == NetworkAgent.INVALID_NETWORK) {
7799                 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
7800                         + Integer.toString(mWifiInfo.score));
7801                 unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
7802             } else if (status == NetworkAgent.VALID_NETWORK) {
7803                 if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
7804                         + Integer.toString(mWifiInfo.score));
7805                 doNetworkStatus(status);
7806             }
7807         }
7808 
7809         @Override
saveAcceptUnvalidated(boolean accept)7810         protected void saveAcceptUnvalidated(boolean accept) {
7811             if (this != mNetworkAgent) return;
7812             WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
7813         }
7814 
7815         @Override
preventAutomaticReconnect()7816         protected void preventAutomaticReconnect() {
7817             if (this != mNetworkAgent) return;
7818             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
7819         }
7820     }
7821 
unwantedNetwork(int reason)7822     void unwantedNetwork(int reason) {
7823         sendMessage(CMD_UNWANTED_NETWORK, reason);
7824     }
7825 
doNetworkStatus(int status)7826     void doNetworkStatus(int status) {
7827         sendMessage(CMD_NETWORK_STATUS, status);
7828     }
7829 
7830     // rfc4186 & rfc4187:
7831     // create Permanent Identity base on IMSI,
7832     // identity = usernam@realm
7833     // with username = prefix | IMSI
7834     // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
buildIdentity(int eapMethod, String imsi, String mccMnc)7835     private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
7836         String mcc;
7837         String mnc;
7838         String prefix;
7839 
7840         if (imsi == null || imsi.isEmpty())
7841             return "";
7842 
7843         if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
7844             prefix = "1";
7845         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
7846             prefix = "0";
7847         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
7848             prefix = "6";
7849         else  // not a valide EapMethod
7850             return "";
7851 
7852         /* extract mcc & mnc from mccMnc */
7853         if (mccMnc != null && !mccMnc.isEmpty()) {
7854             mcc = mccMnc.substring(0, 3);
7855             mnc = mccMnc.substring(3);
7856             if (mnc.length() == 2)
7857                 mnc = "0" + mnc;
7858         } else {
7859             // extract mcc & mnc from IMSI, assume mnc size is 3
7860             mcc = imsi.substring(0, 3);
7861             mnc = imsi.substring(3, 6);
7862         }
7863 
7864         return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
7865     }
7866 
startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList)7867     boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
7868         if (config == null)
7869             return false;
7870 
7871         // We are still seeing a fairly high power consumption triggered by autojoin scans
7872         // Hence do partial scans only for PSK configuration that are roamable since the
7873         // primary purpose of the partial scans is roaming.
7874         // Full badn scans with exponential backoff for the purpose or extended roaming and
7875         // network switching are performed unconditionally.
7876         ScanDetailCache scanDetailCache =
7877                 mWifiConfigStore.getScanDetailCache(config);
7878         if (scanDetailCache == null
7879                 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
7880                 || scanDetailCache.size() > 6) {
7881             //return true but to not trigger the scan
7882             return true;
7883         }
7884         HashSet<Integer> channels = mWifiConfigStore.makeChannelList(config,
7885                 ONE_HOUR_MILLI, restrictChannelList);
7886         if (channels != null && channels.size() != 0) {
7887             StringBuilder freqs = new StringBuilder();
7888             boolean first = true;
7889             for (Integer channel : channels) {
7890                 if (!first)
7891                     freqs.append(",");
7892                 freqs.append(channel.toString());
7893                 first = false;
7894             }
7895             //if (DBG) {
7896             logd("starting scan for " + config.configKey() + " with " + freqs);
7897             //}
7898             // Call wifi native to start the scan
7899             if (startScanNative(
7900                     WifiNative.SCAN_WITHOUT_CONNECTION_SETUP,
7901                     freqs.toString())) {
7902                 // Only count battery consumption if scan request is accepted
7903                 noteScanStart(SCAN_ALARM_SOURCE, null);
7904                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
7905             } else {
7906                 // used for debug only, mark scan as failed
7907                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
7908             }
7909             return true;
7910         } else {
7911             if (DBG) logd("no channels for " + config.configKey());
7912             return false;
7913         }
7914     }
7915 
clearCurrentConfigBSSID(String dbg)7916     void clearCurrentConfigBSSID(String dbg) {
7917         // Clear the bssid in the current config's network block
7918         WifiConfiguration config = getCurrentWifiConfiguration();
7919         if (config == null)
7920             return;
7921         clearConfigBSSID(config, dbg);
7922     }
clearConfigBSSID(WifiConfiguration config, String dbg)7923     void clearConfigBSSID(WifiConfiguration config, String dbg) {
7924         if (config == null)
7925             return;
7926         if (DBG) {
7927             logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
7928                     + " config.bssid " + config.BSSID);
7929         }
7930         config.autoJoinBSSID = "any";
7931         config.BSSID = "any";
7932         if (DBG) {
7933            logd(dbg + " " + config.SSID
7934                     + " nid=" + Integer.toString(config.networkId));
7935         }
7936         mWifiConfigStore.saveWifiConfigBSSID(config);
7937     }
7938 
7939     class L2ConnectedState extends State {
7940         @Override
enter()7941         public void enter() {
7942             mRssiPollToken++;
7943             if (mEnableRssiPolling) {
7944                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
7945             }
7946             if (mNetworkAgent != null) {
7947                 loge("Have NetworkAgent when entering L2Connected");
7948                 setNetworkDetailedState(DetailedState.DISCONNECTED);
7949             }
7950             setNetworkDetailedState(DetailedState.CONNECTING);
7951 
7952             if (!TextUtils.isEmpty(mTcpBufferSizes)) {
7953                 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
7954             }
7955             mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
7956                     "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
7957                     mLinkProperties, 60);
7958 
7959             // We must clear the config BSSID, as the wifi chipset may decide to roam
7960             // from this point on and having the BSSID specified in the network block would
7961             // cause the roam to faile and the device to disconnect
7962             clearCurrentConfigBSSID("L2ConnectedState");
7963 
7964             try {
7965                 mIpReachabilityMonitor = new IpReachabilityMonitor(
7966                         mInterfaceName,
7967                         new IpReachabilityMonitor.Callback() {
7968                             @Override
7969                             public void notifyLost(InetAddress ip, String logMsg) {
7970                                 sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
7971                             }
7972                         });
7973             } catch (IllegalArgumentException e) {
7974                 Log.wtf("Failed to create IpReachabilityMonitor", e);
7975             }
7976         }
7977 
7978         @Override
exit()7979         public void exit() {
7980             if (mIpReachabilityMonitor != null) {
7981                 mIpReachabilityMonitor.stop();
7982                 mIpReachabilityMonitor = null;
7983             }
7984 
7985             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
7986             // Bug: 15347363
7987             // For paranoia's sake, call handleNetworkDisconnect
7988             // only if BSSID is null or last networkId
7989             // is not invalid.
7990             if (DBG) {
7991                 StringBuilder sb = new StringBuilder();
7992                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
7993                 if (mLastBssid !=null) {
7994                     sb.append(" ").append(mLastBssid);
7995                 }
7996             }
7997             if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
7998                 handleNetworkDisconnect();
7999             }
8000         }
8001 
8002         @Override
processMessage(Message message)8003         public boolean processMessage(Message message) {
8004             logStateAndMessage(message, getClass().getSimpleName());
8005 
8006             switch (message.what) {
8007               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
8008                   handlePreDhcpSetup();
8009                   break;
8010               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
8011                   handlePostDhcpSetup();
8012                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
8013                       if (DBG) log("DHCP successful");
8014                       handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS);
8015                       // We advance to mConnectedState because handleIPv4Success will call
8016                       // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL.
8017                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
8018                       mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_DHCP_FAILURE);
8019                       if (DBG) {
8020                           int count = -1;
8021                           WifiConfiguration config = getCurrentWifiConfiguration();
8022                           if (config != null) {
8023                               count = config.numConnectionFailures;
8024                           }
8025                           log("DHCP failure count=" + count);
8026                       }
8027                       handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE);
8028                       // As above, we transition to mDisconnectingState via updateLinkProperties.
8029                   }
8030                   break;
8031                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
8032                     handleSuccessfulIpConfiguration();
8033                     sendConnectedState();
8034                     transitionTo(mConnectedState);
8035                     break;
8036                 case CMD_IP_CONFIGURATION_LOST:
8037                     // Get Link layer stats so that we get fresh tx packet counters.
8038                     getWifiLinkLayerStats(true);
8039                     handleIpConfigurationLost();
8040                     transitionTo(mDisconnectingState);
8041                     break;
8042                 case CMD_IP_REACHABILITY_LOST:
8043                     if (DBG && message.obj != null) log((String) message.obj);
8044                     handleIpReachabilityLost();
8045                     transitionTo(mDisconnectingState);
8046                     break;
8047                 case CMD_DISCONNECT:
8048                     mWifiNative.disconnect();
8049                     transitionTo(mDisconnectingState);
8050                     break;
8051                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
8052                     if (message.arg1 == 1) {
8053                         mWifiNative.disconnect();
8054                         mTemporarilyDisconnectWifi = true;
8055                         transitionTo(mDisconnectingState);
8056                     }
8057                     break;
8058                 case CMD_SET_OPERATIONAL_MODE:
8059                     if (message.arg1 != CONNECT_MODE) {
8060                         sendMessage(CMD_DISCONNECT);
8061                         deferMessage(message);
8062                         if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
8063                             noteWifiDisabledWhileAssociated();
8064                         }
8065                     }
8066                     mWifiConfigStore.
8067                                 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
8068                     break;
8069                 case CMD_SET_COUNTRY_CODE:
8070                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8071                     deferMessage(message);
8072                     break;
8073                 case CMD_START_SCAN:
8074                     if (DBG) {
8075                         logd("CMD_START_SCAN source " + message.arg1
8076                               + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
8077                               + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
8078                               + " targetRoamBSSID=" + mTargetRoamBSSID
8079                               + " RSSI=" + mWifiInfo.getRssi());
8080                     }
8081                     if (message.arg1 == SCAN_ALARM_SOURCE) {
8082                         // Check if the CMD_START_SCAN message is obsolete (and thus if it should
8083                         // not be processed) and restart the scan if neede
8084                         if (!getEnableAutoJoinWhenAssociated()) {
8085                             return HANDLED;
8086                         }
8087                         boolean shouldScan = mScreenOn;
8088 
8089                         if (!checkAndRestartDelayedScan(message.arg2,
8090                                 shouldScan,
8091                                 mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(),
8092                                 null, null)) {
8093                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8094                             logd("L2Connected CMD_START_SCAN source "
8095                                     + message.arg1
8096                                     + " " + message.arg2 + ", " + mDelayedScanCounter
8097                                     + " -> obsolete");
8098                             return HANDLED;
8099                         }
8100                         if (mP2pConnected.get()) {
8101                             logd("L2Connected CMD_START_SCAN source "
8102                                     + message.arg1
8103                                     + " " + message.arg2 + ", " + mDelayedScanCounter
8104                                     + " ignore because P2P is connected");
8105                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8106                             return HANDLED;
8107                         }
8108                         boolean tryFullBandScan = false;
8109                         boolean restrictChannelList = false;
8110                         long now_ms = System.currentTimeMillis();
8111                         if (DBG) {
8112                             logd("CMD_START_SCAN with age="
8113                                     + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
8114                                     + " interval=" + fullBandConnectedTimeIntervalMilli
8115                                     + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
8116                         }
8117                         if (mWifiInfo != null) {
8118                             if (mWifiConfigStore.enableFullBandScanWhenAssociated.get() &&
8119                                     (now_ms - lastFullBandConnectedTimeMilli)
8120                                     > fullBandConnectedTimeIntervalMilli) {
8121                                 if (DBG) {
8122                                     logd("CMD_START_SCAN try full band scan age="
8123                                          + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
8124                                          + " interval=" + fullBandConnectedTimeIntervalMilli
8125                                          + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
8126                                 }
8127                                 tryFullBandScan = true;
8128                             }
8129 
8130                             if (mWifiInfo.txSuccessRate >
8131                                     mWifiConfigStore.maxTxPacketForFullScans
8132                                     || mWifiInfo.rxSuccessRate >
8133                                     mWifiConfigStore.maxRxPacketForFullScans) {
8134                                 // Too much traffic at the interface, hence no full band scan
8135                                 if (DBG) {
8136                                     logd("CMD_START_SCAN " +
8137                                             "prevent full band scan due to pkt rate");
8138                                 }
8139                                 tryFullBandScan = false;
8140                             }
8141 
8142                             if (mWifiInfo.txSuccessRate >
8143                                     mWifiConfigStore.maxTxPacketForPartialScans
8144                                     || mWifiInfo.rxSuccessRate >
8145                                     mWifiConfigStore.maxRxPacketForPartialScans) {
8146                                 // Don't scan if lots of packets are being sent
8147                                 restrictChannelList = true;
8148                                 if (mWifiConfigStore.alwaysEnableScansWhileAssociated.get() == 0) {
8149                                     if (DBG) {
8150                                      logd("CMD_START_SCAN source " + message.arg1
8151                                         + " ...and ignore scans"
8152                                         + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate)
8153                                         + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate));
8154                                     }
8155                                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
8156                                     return HANDLED;
8157                                 }
8158                             }
8159                         }
8160 
8161                         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
8162                         if (DBG) {
8163                             logd("CMD_START_SCAN full=" +
8164                                     tryFullBandScan);
8165                         }
8166                         if (currentConfiguration != null) {
8167                             if (fullBandConnectedTimeIntervalMilli
8168                                     < mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get()) {
8169                                 // Sanity
8170                                 fullBandConnectedTimeIntervalMilli
8171                                         = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
8172                             }
8173                             if (tryFullBandScan) {
8174                                 lastFullBandConnectedTimeMilli = now_ms;
8175                                 if (fullBandConnectedTimeIntervalMilli
8176                                         < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
8177                                     // Increase the interval
8178                                     fullBandConnectedTimeIntervalMilli
8179                                             = fullBandConnectedTimeIntervalMilli
8180                                             * mWifiConfigStore.associatedFullScanBackoff.get() / 8;
8181 
8182                                     if (DBG) {
8183                                         logd("CMD_START_SCAN bump interval ="
8184                                         + fullBandConnectedTimeIntervalMilli);
8185                                     }
8186                                 }
8187                                 handleScanRequest(
8188                                         WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
8189                             } else {
8190                                 if (!startScanForConfiguration(
8191                                         currentConfiguration, restrictChannelList)) {
8192                                     if (DBG) {
8193                                         logd("starting scan, " +
8194                                                 " did not find channels -> full");
8195                                     }
8196                                     lastFullBandConnectedTimeMilli = now_ms;
8197                                     if (fullBandConnectedTimeIntervalMilli
8198                                             < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
8199                                         // Increase the interval
8200                                         fullBandConnectedTimeIntervalMilli
8201                                                 = fullBandConnectedTimeIntervalMilli
8202                                                 * mWifiConfigStore.associatedFullScanBackoff.get() / 8;
8203 
8204                                         if (DBG) {
8205                                             logd("CMD_START_SCAN bump interval ="
8206                                                     + fullBandConnectedTimeIntervalMilli);
8207                                         }
8208                                     }
8209                                     handleScanRequest(
8210                                                 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
8211                                 }
8212                             }
8213 
8214                         } else {
8215                             logd("CMD_START_SCAN : connected mode and no configuration");
8216                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
8217                         }
8218                     } else {
8219                         // Not scan alarm source
8220                         return NOT_HANDLED;
8221                     }
8222                     break;
8223                     /* Ignore connection to same network */
8224                 case WifiManager.CONNECT_NETWORK:
8225                     int netId = message.arg1;
8226                     if (mWifiInfo.getNetworkId() == netId) {
8227                         break;
8228                     }
8229                     return NOT_HANDLED;
8230                     /* Ignore */
8231                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
8232                     break;
8233                 case CMD_RSSI_POLL:
8234                     if (message.arg1 == mRssiPollToken) {
8235                         if (mWifiConfigStore.enableChipWakeUpWhenAssociated.get()) {
8236                             if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
8237                             WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG);
8238                             if (stats != null) {
8239                                 // Sanity check the results provided by driver
8240                                 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
8241                                         && (stats.rssi_mgmt == 0
8242                                         || stats.beacon_rx == 0)) {
8243                                     stats = null;
8244                                 }
8245                             }
8246                             // Get Info and continue polling
8247                             fetchRssiLinkSpeedAndFrequencyNative();
8248                             calculateWifiScore(stats);
8249                         }
8250                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
8251                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
8252 
8253                         if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
8254                     } else {
8255                         // Polling has completed
8256                     }
8257                     break;
8258                 case CMD_ENABLE_RSSI_POLL:
8259                     cleanWifiScore();
8260                     if (mWifiConfigStore.enableRssiPollWhenAssociated.get()) {
8261                         mEnableRssiPolling = (message.arg1 == 1);
8262                     } else {
8263                         mEnableRssiPolling = false;
8264                     }
8265                     mRssiPollToken++;
8266                     if (mEnableRssiPolling) {
8267                         // First poll
8268                         fetchRssiLinkSpeedAndFrequencyNative();
8269                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
8270                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
8271                     }
8272                     break;
8273                 case WifiManager.RSSI_PKTCNT_FETCH:
8274                     RssiPacketCountInfo info = new RssiPacketCountInfo();
8275                     fetchRssiLinkSpeedAndFrequencyNative();
8276                     info.rssi = mWifiInfo.getRssi();
8277                     fetchPktcntNative(info);
8278                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
8279                     break;
8280                 case CMD_DELAYED_NETWORK_DISCONNECT:
8281                     if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) {
8282 
8283                         // Ignore if we are not debouncing
8284                         logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
8285                                 + message.arg1);
8286                         return HANDLED;
8287                     } else {
8288                         logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
8289                                 + message.arg1);
8290 
8291                         linkDebouncing = false;
8292                         // If we are still debouncing while this message comes,
8293                         // it means we were not able to reconnect within the alloted time
8294                         // = LINK_FLAPPING_DEBOUNCE_MSEC
8295                         // and thus, trigger a real disconnect
8296                         handleNetworkDisconnect();
8297                         transitionTo(mDisconnectedState);
8298                     }
8299                     break;
8300                 case CMD_ASSOCIATED_BSSID:
8301                     if ((String) message.obj == null) {
8302                         logw("Associated command w/o BSSID");
8303                         break;
8304                     }
8305                     mLastBssid = (String) message.obj;
8306                     if (mLastBssid != null
8307                             && (mWifiInfo.getBSSID() == null
8308                             || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
8309                         mWifiInfo.setBSSID((String) message.obj);
8310                         sendNetworkStateChangeBroadcast(mLastBssid);
8311                     }
8312                     break;
8313                 default:
8314                     return NOT_HANDLED;
8315             }
8316 
8317             return HANDLED;
8318         }
8319     }
8320 
8321     class ObtainingIpState extends State {
8322         @Override
enter()8323         public void enter() {
8324             if (DBG) {
8325                 String key = "";
8326                 if (getCurrentWifiConfiguration() != null) {
8327                     key = getCurrentWifiConfiguration().configKey();
8328                 }
8329                 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
8330                         + " " + key + " "
8331                         + " roam=" + mAutoRoaming
8332                         + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId)
8333                         + " watchdog= " + obtainingIpWatchdogCount);
8334             }
8335 
8336             // Reset link Debouncing, indicating we have successfully re-connected to the AP
8337             // We might still be roaming
8338             linkDebouncing = false;
8339 
8340             // Send event to CM & network change broadcast
8341             setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
8342 
8343             // We must clear the config BSSID, as the wifi chipset may decide to roam
8344             // from this point on and having the BSSID specified in the network block would
8345             // cause the roam to faile and the device to disconnect
8346             clearCurrentConfigBSSID("ObtainingIpAddress");
8347 
8348             try {
8349                 mNwService.enableIpv6(mInterfaceName);
8350             } catch (RemoteException re) {
8351                 loge("Failed to enable IPv6: " + re);
8352             } catch (IllegalStateException e) {
8353                 loge("Failed to enable IPv6: " + e);
8354             }
8355 
8356             if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
8357                 if (isRoaming()) {
8358                     renewDhcp();
8359                 } else {
8360                     // Remove any IP address on the interface in case we're switching from static
8361                     // IP configuration to DHCP. This is safe because if we get here when not
8362                     // roaming, we don't have a usable address.
8363                     clearIPv4Address(mInterfaceName);
8364                     startDhcp();
8365                 }
8366                 obtainingIpWatchdogCount++;
8367                 logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
8368                 // Get Link layer stats so as we get fresh tx packet counters
8369                 getWifiLinkLayerStats(true);
8370                 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
8371                         obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
8372             } else {
8373                 // stop any running dhcp before assigning static IP
8374                 stopDhcp();
8375                 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration(
8376                         mLastNetworkId);
8377                 if (config.ipAddress == null) {
8378                     logd("Static IP lacks address");
8379                     sendMessage(CMD_STATIC_IP_FAILURE);
8380                 } else {
8381                     InterfaceConfiguration ifcg = new InterfaceConfiguration();
8382                     ifcg.setLinkAddress(config.ipAddress);
8383                     ifcg.setInterfaceUp();
8384                     try {
8385                         mNwService.setInterfaceConfig(mInterfaceName, ifcg);
8386                         if (DBG) log("Static IP configuration succeeded");
8387                         DhcpResults dhcpResults = new DhcpResults(config);
8388                         sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
8389                     } catch (RemoteException re) {
8390                         loge("Static IP configuration failed: " + re);
8391                         sendMessage(CMD_STATIC_IP_FAILURE);
8392                     } catch (IllegalStateException e) {
8393                         loge("Static IP configuration failed: " + e);
8394                         sendMessage(CMD_STATIC_IP_FAILURE);
8395                     }
8396                 }
8397             }
8398         }
8399       @Override
processMessage(Message message)8400       public boolean processMessage(Message message) {
8401           logStateAndMessage(message, getClass().getSimpleName());
8402 
8403           switch(message.what) {
8404               case CMD_STATIC_IP_SUCCESS:
8405                   handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS);
8406                   break;
8407               case CMD_STATIC_IP_FAILURE:
8408                   handleIPv4Failure(CMD_STATIC_IP_FAILURE);
8409                   break;
8410               case CMD_AUTO_CONNECT:
8411               case CMD_AUTO_ROAM:
8412                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8413                   break;
8414               case WifiManager.SAVE_NETWORK:
8415               case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
8416                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8417                   deferMessage(message);
8418                   break;
8419                   /* Defer any power mode changes since we must keep active power mode at DHCP */
8420               case CMD_SET_HIGH_PERF_MODE:
8421                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8422                   deferMessage(message);
8423                   break;
8424                   /* Defer scan request since we should not switch to other channels at DHCP */
8425               case CMD_START_SCAN:
8426                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8427                   deferMessage(message);
8428                   break;
8429               case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
8430                   if (message.arg1 == obtainingIpWatchdogCount) {
8431                       logd("ObtainingIpAddress: Watchdog Triggered, count="
8432                               + obtainingIpWatchdogCount);
8433                       handleIpConfigurationLost();
8434                       transitionTo(mDisconnectingState);
8435                       break;
8436                   }
8437                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8438                   break;
8439               default:
8440                   return NOT_HANDLED;
8441           }
8442           return HANDLED;
8443       }
8444     }
8445 
8446     // Note: currently, this state is never used, because WifiWatchdogStateMachine unconditionally
8447     // sets mPoorNetworkDetectionEnabled to false.
8448     class VerifyingLinkState extends State {
8449         @Override
enter()8450         public void enter() {
8451             log(getName() + " enter");
8452             setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
8453             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
8454             sendNetworkStateChangeBroadcast(mLastBssid);
8455             // End roaming
8456             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
8457         }
8458         @Override
processMessage(Message message)8459         public boolean processMessage(Message message) {
8460             logStateAndMessage(message, getClass().getSimpleName());
8461 
8462             switch (message.what) {
8463                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
8464                     // Stay here
8465                     log(getName() + " POOR_LINK_DETECTED: no transition");
8466                     break;
8467                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
8468                     log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED");
8469                     sendConnectedState();
8470                     transitionTo(mConnectedState);
8471                     break;
8472                 default:
8473                     if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED");
8474                     return NOT_HANDLED;
8475             }
8476             return HANDLED;
8477         }
8478     }
8479 
sendConnectedState()8480     private void sendConnectedState() {
8481         // If this network was explicitly selected by the user, evaluate whether to call
8482         // explicitlySelected() so the system can treat it appropriately.
8483         WifiConfiguration config = getCurrentWifiConfiguration();
8484         if (mWifiConfigStore.isLastSelectedConfiguration(config)) {
8485             boolean prompt = mWifiConfigStore.checkConfigOverridePermission(config.lastConnectUid);
8486             if (DBG) {
8487                 log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
8488             }
8489             if (prompt) {
8490                 // Selected by the user via Settings or QuickSettings. If this network has Internet
8491                 // access, switch to it. Otherwise, switch to it only if the user confirms that they
8492                 // really want to switch, or has already confirmed and selected "Don't ask again".
8493                 if (DBG) {
8494                     log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
8495                 }
8496                 mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
8497             }
8498         }
8499 
8500         setNetworkDetailedState(DetailedState.CONNECTED);
8501         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
8502         sendNetworkStateChangeBroadcast(mLastBssid);
8503     }
8504 
8505     class RoamingState extends State {
8506         boolean mAssociated;
8507         @Override
enter()8508         public void enter() {
8509             if (DBG) {
8510                 log("RoamingState Enter"
8511                         + " mScreenOn=" + mScreenOn );
8512             }
8513             setScanAlarm(false);
8514 
8515             // Make sure we disconnect if roaming fails
8516             roamWatchdogCount++;
8517             logd("Start Roam Watchdog " + roamWatchdogCount);
8518             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
8519                     roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
8520             mAssociated = false;
8521         }
8522         @Override
processMessage(Message message)8523         public boolean processMessage(Message message) {
8524             logStateAndMessage(message, getClass().getSimpleName());
8525             WifiConfiguration config;
8526             switch (message.what) {
8527                 case CMD_IP_CONFIGURATION_LOST:
8528                     config = getCurrentWifiConfiguration();
8529                     if (config != null) {
8530                         mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
8531                         mWifiConfigStore.noteRoamingFailure(config,
8532                                 WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
8533                     }
8534                     return NOT_HANDLED;
8535                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
8536                     if (DBG) log("Roaming and Watchdog reports poor link -> ignore");
8537                     return HANDLED;
8538                 case CMD_UNWANTED_NETWORK:
8539                     if (DBG) log("Roaming and CS doesnt want the network -> ignore");
8540                     return HANDLED;
8541                 case CMD_SET_OPERATIONAL_MODE:
8542                     if (message.arg1 != CONNECT_MODE) {
8543                         deferMessage(message);
8544                     }
8545                     break;
8546                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8547                     /**
8548                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
8549                      * before NETWORK_DISCONNECTION_EVENT
8550                      * And there is an associated BSSID corresponding to our target BSSID, then
8551                      * we have missed the network disconnection, transition to mDisconnectedState
8552                      * and handle the rest of the events there.
8553                      */
8554                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
8555                     if (stateChangeResult.state == SupplicantState.DISCONNECTED
8556                             || stateChangeResult.state == SupplicantState.INACTIVE
8557                             || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
8558                         if (DBG) {
8559                             log("STATE_CHANGE_EVENT in roaming state "
8560                                     + stateChangeResult.toString() );
8561                         }
8562                         if (stateChangeResult.BSSID != null
8563                                 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
8564                             handleNetworkDisconnect();
8565                             transitionTo(mDisconnectedState);
8566                         }
8567                     }
8568                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
8569                         // We completed the layer2 roaming part
8570                         mAssociated = true;
8571                         if (stateChangeResult.BSSID != null) {
8572                             mTargetRoamBSSID = (String) stateChangeResult.BSSID;
8573                         }
8574                     }
8575                     break;
8576                 case CMD_ROAM_WATCHDOG_TIMER:
8577                     if (roamWatchdogCount == message.arg1) {
8578                         if (DBG) log("roaming watchdog! -> disconnect");
8579                         mRoamFailCount++;
8580                         handleNetworkDisconnect();
8581                         mWifiNative.disconnect();
8582                         transitionTo(mDisconnectedState);
8583                     }
8584                     break;
8585                case WifiMonitor.NETWORK_CONNECTION_EVENT:
8586                    if (mAssociated) {
8587                        if (DBG) log("roaming and Network connection established");
8588                        mLastNetworkId = message.arg1;
8589                        mLastBssid = (String) message.obj;
8590                        mWifiInfo.setBSSID(mLastBssid);
8591                        mWifiInfo.setNetworkId(mLastNetworkId);
8592                        mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true);
8593                        sendNetworkStateChangeBroadcast(mLastBssid);
8594                        transitionTo(mObtainingIpState);
8595                    } else {
8596                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8597                    }
8598                    break;
8599                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8600                    // Throw away but only if it corresponds to the network we're roaming to
8601                    String bssid = (String)message.obj;
8602                    if (true) {
8603                        String target = "";
8604                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
8605                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
8606                                + " BSSID=" + bssid
8607                                + " target=" + target);
8608                    }
8609                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
8610                        handleNetworkDisconnect();
8611                        transitionTo(mDisconnectedState);
8612                    }
8613                    break;
8614                 case WifiMonitor.SSID_TEMP_DISABLED:
8615                     // Auth error while roaming
8616                     logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
8617                             + " id=" + Integer.toString(message.arg1)
8618                             + " isRoaming=" + isRoaming()
8619                             + " roam=" + Integer.toString(mAutoRoaming));
8620                     if (message.arg1 == mLastNetworkId) {
8621                         config = getCurrentWifiConfiguration();
8622                         if (config != null) {
8623                             mWifiLogger.captureBugReportData(
8624                                     WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
8625                             mWifiConfigStore.noteRoamingFailure(config,
8626                                     WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
8627                         }
8628                         handleNetworkDisconnect();
8629                         transitionTo(mDisconnectingState);
8630                     }
8631                     return NOT_HANDLED;
8632                 case CMD_START_SCAN:
8633                     deferMessage(message);
8634                     break;
8635                 default:
8636                     return NOT_HANDLED;
8637             }
8638             return HANDLED;
8639         }
8640 
8641         @Override
exit()8642         public void exit() {
8643             logd("WifiStateMachine: Leaving Roaming state");
8644         }
8645     }
8646 
8647     class ConnectedState extends State {
8648         @Override
enter()8649         public void enter() {
8650             String address;
8651             updateDefaultRouteMacAddress(1000);
8652             if (DBG) {
8653                 log("Enter ConnectedState "
8654                        + " mScreenOn=" + mScreenOn
8655                        + " scanperiod="
8656                        + Integer.toString(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get())
8657                        + " useGscan=" + mHalBasedPnoDriverSupported + "/"
8658                         + mWifiConfigStore.enableHalBasedPno.get()
8659                         + " mHalBasedPnoEnableInDevSettings " + mHalBasedPnoEnableInDevSettings);
8660             }
8661             if (mScreenOn
8662                     && getEnableAutoJoinWhenAssociated()) {
8663                 if (useHalBasedAutoJoinOffload()) {
8664                     startGScanConnectedModeOffload("connectedEnter");
8665                 } else {
8666                     // restart scan alarm
8667                     startDelayedScan(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(),
8668                             null, null);
8669                 }
8670             }
8671             registerConnected();
8672             lastConnectAttemptTimestamp = 0;
8673             targetWificonfiguration = null;
8674             // Paranoia
8675             linkDebouncing = false;
8676 
8677             // Not roaming anymore
8678             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
8679 
8680             if (testNetworkDisconnect) {
8681                 testNetworkDisconnectCounter++;
8682                 logd("ConnectedState Enter start disconnect test " +
8683                         testNetworkDisconnectCounter);
8684                 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
8685                         testNetworkDisconnectCounter, 0), 15000);
8686             }
8687 
8688             // Reenable all networks, allow for hidden networks to be scanned
8689             mWifiConfigStore.enableAllNetworks();
8690 
8691             mLastDriverRoamAttempt = 0;
8692 
8693             //startLazyRoam();
8694         }
8695         @Override
processMessage(Message message)8696         public boolean processMessage(Message message) {
8697             WifiConfiguration config = null;
8698             logStateAndMessage(message, getClass().getSimpleName());
8699 
8700             switch (message.what) {
8701                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
8702                     if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
8703                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8704                         return HANDLED;
8705                     }
8706                     /* If we are still in Disconnected state after having discovered a valid
8707                      * network this means autojoin didnt managed to associate to the network,
8708                      * then restart PNO so as we will try associating to it again.
8709                      */
8710                     if (useHalBasedAutoJoinOffload()) {
8711                         if (mGScanStartTimeMilli == 0) {
8712                             // If offload is not started, then start it...
8713                             startGScanConnectedModeOffload("connectedRestart");
8714                         } else {
8715                             // If offload is already started, then check if we need to increase
8716                             // the scan period and restart the Gscan
8717                             long now = System.currentTimeMillis();
8718                             if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
8719                                     && ((now - mGScanStartTimeMilli)
8720                                     > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
8721                                 && (mGScanPeriodMilli
8722                                     < mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get()))
8723                             {
8724                                 startConnectedGScan("Connected restart gscan");
8725                             }
8726                         }
8727                     }
8728                     break;
8729                 case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
8730                     updateAssociatedScanPermission();
8731                     break;
8732                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
8733                     if (DBG) log("Watchdog reports poor link");
8734                     transitionTo(mVerifyingLinkState);
8735                     break;
8736                 case CMD_UNWANTED_NETWORK:
8737                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
8738                         mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo);
8739                         mWifiNative.disconnect();
8740                         transitionTo(mDisconnectingState);
8741                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
8742                             message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
8743                         config = getCurrentWifiConfiguration();
8744                         if (config != null) {
8745                             // Disable autojoin
8746                             if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
8747                                 config.validatedInternetAccess = false;
8748                                 // Clear last-selected status, as being last-selected also avoids
8749                                 // disabling auto-join.
8750                                 if (mWifiConfigStore.isLastSelectedConfiguration(config)) {
8751                                     mWifiConfigStore.setLastSelectedConfiguration(
8752                                         WifiConfiguration.INVALID_NETWORK_ID);
8753                                 }
8754                             }
8755                             config.numNoInternetAccessReports += 1;
8756                             config.dirty = true;
8757                             mWifiConfigStore.writeKnownNetworkHistory(false);
8758                         }
8759                     }
8760                     return HANDLED;
8761                 case CMD_NETWORK_STATUS:
8762                     if (message.arg1 == NetworkAgent.VALID_NETWORK) {
8763                         config = getCurrentWifiConfiguration();
8764                         if (config != null) {
8765                             if (!config.validatedInternetAccess
8766                                     || config.numNoInternetAccessReports != 0) {
8767                                 config.dirty = true;
8768                             }
8769                             // re-enable autojoin
8770                             config.numNoInternetAccessReports = 0;
8771                             config.validatedInternetAccess = true;
8772                             mWifiConfigStore.writeKnownNetworkHistory(false);
8773                         }
8774                     }
8775                     return HANDLED;
8776                 case CMD_ACCEPT_UNVALIDATED:
8777                     boolean accept = (message.arg1 != 0);
8778                     config = getCurrentWifiConfiguration();
8779                     if (config != null) {
8780                         config.noInternetAccessExpected = accept;
8781                     }
8782                     return HANDLED;
8783                 case CMD_TEST_NETWORK_DISCONNECT:
8784                     // Force a disconnect
8785                     if (message.arg1 == testNetworkDisconnectCounter) {
8786                         mWifiNative.disconnect();
8787                     }
8788                     break;
8789                 case CMD_ASSOCIATED_BSSID:
8790                     // ASSOCIATING to a new BSSID while already connected, indicates
8791                     // that driver is roaming
8792                     mLastDriverRoamAttempt = System.currentTimeMillis();
8793                     String toBSSID = (String)message.obj;
8794                     if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) {
8795                         mWifiConfigStore.driverRoamedFrom(mWifiInfo);
8796                     }
8797                     return NOT_HANDLED;
8798                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8799                     long lastRoam = 0;
8800                     if (mLastDriverRoamAttempt != 0) {
8801                         // Calculate time since last driver roam attempt
8802                         lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
8803                         mLastDriverRoamAttempt = 0;
8804                     }
8805                     if (unexpectedDisconnectedReason(message.arg2)) {
8806                         mWifiLogger.captureBugReportData(
8807                                 WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
8808                     }
8809                     config = getCurrentWifiConfiguration();
8810                     if (mScreenOn
8811                             && !linkDebouncing
8812                             && config != null
8813                             && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED
8814                             && !mWifiConfigStore.isLastSelectedConfiguration(config)
8815                             && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
8816                                 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
8817                             && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
8818                                     && mWifiInfo.getRssi() >
8819                                     WifiConfiguration.BAD_RSSI_24)
8820                                     || (ScanResult.is5GHz(mWifiInfo.getFrequency())
8821                                     && mWifiInfo.getRssi() >
8822                                     WifiConfiguration.BAD_RSSI_5))) {
8823                         // Start de-bouncing the L2 disconnection:
8824                         // this L2 disconnection might be spurious.
8825                         // Hence we allow 7 seconds for the state machine to try
8826                         // to reconnect, go thru the
8827                         // roaming cycle and enter Obtaining IP address
8828                         // before signalling the disconnect to ConnectivityService and L3
8829                         startScanForConfiguration(getCurrentWifiConfiguration(), false);
8830                         linkDebouncing = true;
8831 
8832                         sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
8833                                 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
8834                         if (DBG) {
8835                             log("NETWORK_DISCONNECTION_EVENT in connected state"
8836                                     + " BSSID=" + mWifiInfo.getBSSID()
8837                                     + " RSSI=" + mWifiInfo.getRssi()
8838                                     + " freq=" + mWifiInfo.getFrequency()
8839                                     + " reason=" + message.arg2
8840                                     + " -> debounce");
8841                         }
8842                         return HANDLED;
8843                     } else {
8844                         if (DBG) {
8845                             int ajst = -1;
8846                             if (config != null) ajst = config.autoJoinStatus;
8847                             log("NETWORK_DISCONNECTION_EVENT in connected state"
8848                                     + " BSSID=" + mWifiInfo.getBSSID()
8849                                     + " RSSI=" + mWifiInfo.getRssi()
8850                                     + " freq=" + mWifiInfo.getFrequency()
8851                                     + " was debouncing=" + linkDebouncing
8852                                     + " reason=" + message.arg2
8853                                     + " ajst=" + ajst);
8854                         }
8855                     }
8856                     break;
8857                 case CMD_AUTO_ROAM:
8858                     // Clear the driver roam indication since we are attempting a framework roam
8859                     mLastDriverRoamAttempt = 0;
8860 
8861                     /* Connect command coming from auto-join */
8862                     ScanResult candidate = (ScanResult)message.obj;
8863                     String bssid = "any";
8864                     if (candidate != null && candidate.is5GHz()) {
8865                         // Only lock BSSID for 5GHz networks
8866                         bssid = candidate.BSSID;
8867                     }
8868                     int netId = mLastNetworkId;
8869                     config = getCurrentWifiConfiguration();
8870 
8871 
8872                     if (config == null) {
8873                         loge("AUTO_ROAM and no config, bail out...");
8874                         break;
8875                     }
8876 
8877                     logd("CMD_AUTO_ROAM sup state "
8878                             + mSupplicantStateTracker.getSupplicantStateName()
8879                             + " my state " + getCurrentState().getName()
8880                             + " nid=" + Integer.toString(netId)
8881                             + " config " + config.configKey()
8882                             + " roam=" + Integer.toString(message.arg2)
8883                             + " to " + bssid
8884                             + " targetRoamBSSID " + mTargetRoamBSSID);
8885 
8886                     /* Save the BSSID so as to lock it @ firmware */
8887                     if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) {
8888                         logd("AUTO_ROAM nothing to do");
8889                         // Same BSSID, nothing to do
8890                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8891                         break;
8892                     };
8893 
8894                     // Make sure the network is enabled, since supplicant will not re-enable it
8895                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
8896 
8897                     if (deferForUserInput(message, netId, false)) {
8898                         break;
8899                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
8900                             WifiConfiguration.USER_BANNED) {
8901                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8902                                 WifiManager.NOT_AUTHORIZED);
8903                         break;
8904                     }
8905 
8906                     boolean ret = false;
8907                     if (mLastNetworkId != netId) {
8908                        if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false,
8909                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
8910                            ret = true;
8911                        }
8912                     } else {
8913                          ret = mWifiNative.reassociate();
8914                     }
8915                     if (ret) {
8916                         lastConnectAttemptTimestamp = System.currentTimeMillis();
8917                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
8918 
8919                         // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
8920                         mAutoRoaming = message.arg2;
8921                         transitionTo(mRoamingState);
8922 
8923                     } else {
8924                         loge("Failed to connect config: " + config + " netId: " + netId);
8925                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8926                                 WifiManager.ERROR);
8927                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
8928                         break;
8929                     }
8930                     break;
8931                 default:
8932                     return NOT_HANDLED;
8933             }
8934             return HANDLED;
8935         }
8936 
8937         @Override
exit()8938         public void exit() {
8939             logd("WifiStateMachine: Leaving Connected state");
8940             setScanAlarm(false);
8941             mLastDriverRoamAttempt = 0;
8942 
8943             stopLazyRoam();
8944 
8945             mWhiteListedSsids = null;
8946         }
8947     }
8948 
8949     class DisconnectingState extends State {
8950 
8951         @Override
enter()8952         public void enter() {
8953 
8954             if (PDBG) {
8955                 logd(" Enter DisconnectingState State scan interval "
8956                         + mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
8957                         + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
8958                         + " screenOn=" + mScreenOn);
8959             }
8960 
8961             // Make sure we disconnect: we enter this state prior to connecting to a new
8962             // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
8963             // event which in this case will be indicating that supplicant started to associate.
8964             // In some cases supplicant doesn't ignore the connect requests (it might not
8965             // find the target SSID in its cache),
8966             // Therefore we end up stuck that state, hence the need for the watchdog.
8967             disconnectingWatchdogCount++;
8968             logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
8969             sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
8970                     disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
8971         }
8972 
8973         @Override
processMessage(Message message)8974         public boolean processMessage(Message message) {
8975             logStateAndMessage(message, getClass().getSimpleName());
8976             switch (message.what) {
8977                 case CMD_SET_OPERATIONAL_MODE:
8978                     if (message.arg1 != CONNECT_MODE) {
8979                         deferMessage(message);
8980                     }
8981                     break;
8982                 case CMD_START_SCAN:
8983                     deferMessage(message);
8984                     return HANDLED;
8985                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
8986                     if (disconnectingWatchdogCount == message.arg1) {
8987                         if (DBG) log("disconnecting watchdog! -> disconnect");
8988                         handleNetworkDisconnect();
8989                         transitionTo(mDisconnectedState);
8990                     }
8991                     break;
8992                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8993                     /**
8994                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
8995                      * we have missed the network disconnection, transition to mDisconnectedState
8996                      * and handle the rest of the events there
8997                      */
8998                     deferMessage(message);
8999                     handleNetworkDisconnect();
9000                     transitionTo(mDisconnectedState);
9001                     break;
9002                 default:
9003                     return NOT_HANDLED;
9004             }
9005             return HANDLED;
9006         }
9007     }
9008 
9009     class DisconnectedState extends State {
9010         @Override
enter()9011         public void enter() {
9012             // We dont scan frequently if this is a temporary disconnect
9013             // due to p2p
9014             if (mTemporarilyDisconnectWifi) {
9015                 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
9016                 return;
9017             }
9018 
9019             if (PDBG) {
9020                 logd(" Enter DisconnectedState scan interval "
9021                         + mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
9022                         + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
9023                         + " screenOn=" + mScreenOn
9024                         + " useGscan=" + mHalBasedPnoDriverSupported + "/"
9025                         + mWifiConfigStore.enableHalBasedPno.get());
9026             }
9027 
9028             /** clear the roaming state, if we were roaming, we failed */
9029             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
9030 
9031             if (useHalBasedAutoJoinOffload()) {
9032                 startGScanDisconnectedModeOffload("disconnectedEnter");
9033             } else {
9034                 if (mScreenOn) {
9035                     /**
9036                      * screen lit and => delayed timer
9037                      */
9038                     startDelayedScan(500, null, null);
9039                 } else {
9040                     /**
9041                      * screen dark and PNO supported => scan alarm disabled
9042                      */
9043                     if (mBackgroundScanSupported) {
9044                         /* If a regular scan result is pending, do not initiate background
9045                          * scan until the scan results are returned. This is needed because
9046                         * initiating a background scan will cancel the regular scan and
9047                         * scan results will not be returned until background scanning is
9048                         * cleared
9049                         */
9050                         if (!mIsScanOngoing) {
9051                             enableBackgroundScan(true);
9052                         }
9053                     } else {
9054                         setScanAlarm(true);
9055                     }
9056                 }
9057             }
9058 
9059             /**
9060              * If we have no networks saved, the supplicant stops doing the periodic scan.
9061              * The scans are useful to notify the user of the presence of an open network.
9062              * Note that these are not wake up scans.
9063              */
9064             if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
9065                     && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
9066                 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
9067                         ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
9068             }
9069 
9070             mDisconnectedTimeStamp = System.currentTimeMillis();
9071             mDisconnectedPnoAlarmCount = 0;
9072         }
9073         @Override
processMessage(Message message)9074         public boolean processMessage(Message message) {
9075             boolean ret = HANDLED;
9076 
9077             logStateAndMessage(message, getClass().getSimpleName());
9078 
9079             switch (message.what) {
9080                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
9081                     if (mP2pConnected.get()) break;
9082                     if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
9083                             mWifiConfigStore.getConfiguredNetworks().size() == 0) {
9084                         startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
9085                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
9086                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
9087                     }
9088                     break;
9089                 case WifiManager.FORGET_NETWORK:
9090                 case CMD_REMOVE_NETWORK:
9091                 case CMD_REMOVE_APP_CONFIGURATIONS:
9092                 case CMD_REMOVE_USER_CONFIGURATIONS:
9093                     // Set up a delayed message here. After the forget/remove is handled
9094                     // the handled delayed message will determine if there is a need to
9095                     // scan and continue
9096                     sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
9097                                 ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
9098                     ret = NOT_HANDLED;
9099                     break;
9100                 case CMD_SET_OPERATIONAL_MODE:
9101                     if (message.arg1 != CONNECT_MODE) {
9102                         mOperationalMode = message.arg1;
9103 
9104                         mWifiConfigStore.disableAllNetworks();
9105                         if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
9106                             mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
9107                             setWifiState(WIFI_STATE_DISABLED);
9108                         }
9109                         transitionTo(mScanModeState);
9110                     }
9111                     mWifiConfigStore.
9112                             setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
9113                     break;
9114                     /* Ignore network disconnect */
9115                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
9116                     break;
9117                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
9118                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
9119                     if (DBG) {
9120                         logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
9121                                 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
9122                                 + " debouncing=" + linkDebouncing);
9123                     }
9124                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
9125                     /* ConnectModeState does the rest of the handling */
9126                     ret = NOT_HANDLED;
9127                     break;
9128                 case CMD_START_SCAN:
9129                     if (!checkOrDeferScanAllowed(message)) {
9130                         // The scan request was rescheduled
9131                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
9132                         return HANDLED;
9133                     }
9134                     if (message.arg1 == SCAN_ALARM_SOURCE) {
9135                         // Check if the CMD_START_SCAN message is obsolete (and thus if it should
9136                         // not be processed) and restart the scan
9137                         int period =  mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get();
9138                         if (mP2pConnected.get()) {
9139                            period = (int)Settings.Global.getLong(mContext.getContentResolver(),
9140                                     Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
9141                                     period);
9142                         }
9143                         if (!checkAndRestartDelayedScan(message.arg2,
9144                                 true, period, null, null)) {
9145                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
9146                             logd("Disconnected CMD_START_SCAN source "
9147                                     + message.arg1
9148                                     + " " + message.arg2 + ", " + mDelayedScanCounter
9149                                     + " -> obsolete");
9150                             return HANDLED;
9151                         }
9152                         /* Disable background scan temporarily during a regular scan */
9153                         enableBackgroundScan(false);
9154                         handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
9155                         ret = HANDLED;
9156                     } else {
9157 
9158                         /*
9159                          * The SCAN request is not handled in this state and
9160                          * would eventually might/will get handled in the
9161                          * parent's state. The PNO, if already enabled had to
9162                          * get disabled before the SCAN trigger. Hence, stop
9163                          * the PNO if already enabled in this state, though the
9164                          * SCAN request is not handled(PNO disable before the
9165                          * SCAN trigger in any other state is not the right
9166                          * place to issue).
9167                          */
9168 
9169                         enableBackgroundScan(false);
9170                         ret = NOT_HANDLED;
9171                     }
9172                     break;
9173                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
9174                     if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
9175                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
9176                         return HANDLED;
9177                     }
9178                     /* If we are still in Disconnected state after having discovered a valid
9179                      * network this means autojoin didnt managed to associate to the network,
9180                      * then restart PNO so as we will try associating to it again.
9181                      */
9182                     if (useHalBasedAutoJoinOffload()) {
9183                         if (mGScanStartTimeMilli == 0) {
9184                             // If offload is not started, then start it...
9185                             startGScanDisconnectedModeOffload("disconnectedRestart");
9186                         } else {
9187                             // If offload is already started, then check if we need to increase
9188                             // the scan period and restart the Gscan
9189                             long now = System.currentTimeMillis();
9190                             if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
9191                                     && ((now - mGScanStartTimeMilli)
9192                                     > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
9193                                     && (mGScanPeriodMilli
9194                                     < mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get()))
9195                             {
9196                                 startDisconnectedGScan("disconnected restart gscan");
9197                             }
9198                         }
9199                     } else {
9200                         // If we are still disconnected for a short while after having found a
9201                         // network thru PNO, then something went wrong, and for some reason we
9202                         // couldn't join this network.
9203                         // It might be due to a SW bug in supplicant or the wifi stack, or an
9204                         // interoperability issue, or we try to join a bad bss and failed
9205                         // In that case we want to restart pno so as to make sure that we will
9206                         // attempt again to join that network.
9207                         if (!mScreenOn && !mIsScanOngoing && mBackgroundScanSupported) {
9208                             enableBackgroundScan(false);
9209                             enableBackgroundScan(true);
9210                         }
9211                         return HANDLED;
9212                     }
9213                     break;
9214                 case WifiMonitor.SCAN_RESULTS_EVENT:
9215                 case WifiMonitor.SCAN_FAILED_EVENT:
9216                     /* Re-enable background scan when a pending scan result is received */
9217                     if (!mScreenOn && mIsScanOngoing
9218                             && mBackgroundScanSupported
9219                             && !useHalBasedAutoJoinOffload()) {
9220                         enableBackgroundScan(true);
9221                     } else if (!mScreenOn
9222                             && !mIsScanOngoing
9223                             && mBackgroundScanSupported
9224                             && !useHalBasedAutoJoinOffload()) {
9225                         // We receive scan results from legacy PNO, hence restart the PNO alarm
9226                         int delay;
9227                         if (mDisconnectedPnoAlarmCount < 1) {
9228                             delay = 30 * 1000;
9229                         } else if (mDisconnectedPnoAlarmCount < 3) {
9230                             delay = 60 * 1000;
9231                         } else {
9232                             delay = 360 * 1000;
9233                         }
9234                         mDisconnectedPnoAlarmCount++;
9235                         if (VDBG) {
9236                             logd("Starting PNO alarm " + delay);
9237                         }
9238                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
9239                                 System.currentTimeMillis() + delay,
9240                                 mPnoIntent);
9241                     }
9242                     /* Handled in parent state */
9243                     ret = NOT_HANDLED;
9244                     break;
9245                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
9246                     NetworkInfo info = (NetworkInfo) message.obj;
9247                     mP2pConnected.set(info.isConnected());
9248                     if (mP2pConnected.get()) {
9249                         int defaultInterval = mContext.getResources().getInteger(
9250                                 R.integer.config_wifi_scan_interval_p2p_connected);
9251                         long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
9252                                 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
9253                                 defaultInterval);
9254                         mWifiNative.setScanInterval((int) scanIntervalMs/1000);
9255                     } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
9256                         if (DBG) log("Turn on scanning after p2p disconnected");
9257                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
9258                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
9259                     } else {
9260                         // If P2P is not connected and there are saved networks, then restart
9261                         // scanning at the normal period. This is necessary because scanning might
9262                         // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
9263                         // was set to zero.
9264                         if (useHalBasedAutoJoinOffload()) {
9265                             startGScanDisconnectedModeOffload("p2pRestart");
9266                         } else {
9267                             startDelayedScan(
9268                                     mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get(),
9269                                     null, null);
9270                         }
9271                     }
9272                     break;
9273                 case CMD_RECONNECT:
9274                 case CMD_REASSOCIATE:
9275                     if (mTemporarilyDisconnectWifi) {
9276                         // Drop a third party reconnect/reassociate if STA is
9277                         // temporarily disconnected for p2p
9278                         break;
9279                     } else {
9280                         // ConnectModeState handles it
9281                         ret = NOT_HANDLED;
9282                     }
9283                     break;
9284                 case CMD_SCREEN_STATE_CHANGED:
9285                     handleScreenStateChanged(message.arg1 != 0);
9286                     break;
9287                 default:
9288                     ret = NOT_HANDLED;
9289             }
9290             return ret;
9291         }
9292 
9293         @Override
exit()9294         public void exit() {
9295             mDisconnectedPnoAlarmCount = 0;
9296             /* No need for a background scan upon exit from a disconnected state */
9297             enableBackgroundScan(false);
9298             setScanAlarm(false);
9299             mAlarmManager.cancel(mPnoIntent);
9300         }
9301     }
9302 
9303     class WpsRunningState extends State {
9304         // Tracks the source to provide a reply
9305         private Message mSourceMessage;
9306         @Override
enter()9307         public void enter() {
9308             mSourceMessage = Message.obtain(getCurrentMessage());
9309         }
9310         @Override
processMessage(Message message)9311         public boolean processMessage(Message message) {
9312             logStateAndMessage(message, getClass().getSimpleName());
9313 
9314             switch (message.what) {
9315                 case WifiMonitor.WPS_SUCCESS_EVENT:
9316                     // Ignore intermediate success, wait for full connection
9317                     break;
9318                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
9319                     replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
9320                     mSourceMessage.recycle();
9321                     mSourceMessage = null;
9322                     deferMessage(message);
9323                     transitionTo(mDisconnectedState);
9324                     break;
9325                 case WifiMonitor.WPS_OVERLAP_EVENT:
9326                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
9327                             WifiManager.WPS_OVERLAP_ERROR);
9328                     mSourceMessage.recycle();
9329                     mSourceMessage = null;
9330                     transitionTo(mDisconnectedState);
9331                     break;
9332                 case WifiMonitor.WPS_FAIL_EVENT:
9333                     // Arg1 has the reason for the failure
9334                     if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
9335                         replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
9336                         mSourceMessage.recycle();
9337                         mSourceMessage = null;
9338                         transitionTo(mDisconnectedState);
9339                     } else {
9340                         if (DBG) log("Ignore unspecified fail event during WPS connection");
9341                     }
9342                     break;
9343                 case WifiMonitor.WPS_TIMEOUT_EVENT:
9344                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
9345                             WifiManager.WPS_TIMED_OUT);
9346                     mSourceMessage.recycle();
9347                     mSourceMessage = null;
9348                     transitionTo(mDisconnectedState);
9349                     break;
9350                 case WifiManager.START_WPS:
9351                     replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
9352                     break;
9353                 case WifiManager.CANCEL_WPS:
9354                     if (mWifiNative.cancelWps()) {
9355                         replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
9356                     } else {
9357                         replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
9358                     }
9359                     transitionTo(mDisconnectedState);
9360                     break;
9361                 /**
9362                  * Defer all commands that can cause connections to a different network
9363                  * or put the state machine out of connect mode
9364                  */
9365                 case CMD_STOP_DRIVER:
9366                 case CMD_SET_OPERATIONAL_MODE:
9367                 case WifiManager.CONNECT_NETWORK:
9368                 case CMD_ENABLE_NETWORK:
9369                 case CMD_RECONNECT:
9370                 case CMD_REASSOCIATE:
9371                 case CMD_ENABLE_ALL_NETWORKS:
9372                     deferMessage(message);
9373                     break;
9374                 case CMD_AUTO_CONNECT:
9375                 case CMD_AUTO_ROAM:
9376                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
9377                     return HANDLED;
9378                 case CMD_START_SCAN:
9379                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
9380                     return HANDLED;
9381                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
9382                     if (DBG) log("Network connection lost");
9383                     handleNetworkDisconnect();
9384                     break;
9385                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
9386                     if (DBG) log("Ignore Assoc reject event during WPS Connection");
9387                     break;
9388                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
9389                     // Disregard auth failure events during WPS connection. The
9390                     // EAP sequence is retried several times, and there might be
9391                     // failures (especially for wps pin). We will get a WPS_XXX
9392                     // event at the end of the sequence anyway.
9393                     if (DBG) log("Ignore auth failure during WPS connection");
9394                     break;
9395                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
9396                     // Throw away supplicant state changes when WPS is running.
9397                     // We will start getting supplicant state changes once we get
9398                     // a WPS success or failure
9399                     break;
9400                 default:
9401                     return NOT_HANDLED;
9402             }
9403             return HANDLED;
9404         }
9405 
9406         @Override
exit()9407         public void exit() {
9408             mWifiConfigStore.enableAllNetworks();
9409             mWifiConfigStore.loadConfiguredNetworks();
9410         }
9411     }
9412 
9413     class SoftApStartingState extends State {
9414         @Override
enter()9415         public void enter() {
9416             final Message message = getCurrentMessage();
9417             if (message.what == CMD_START_AP) {
9418                 final WifiConfiguration config = (WifiConfiguration) message.obj;
9419 
9420                 if (config == null) {
9421                     mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
9422                 } else {
9423                     mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
9424                     startSoftApWithConfig(config);
9425                 }
9426             } else {
9427                 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
9428             }
9429         }
9430         @Override
processMessage(Message message)9431         public boolean processMessage(Message message) {
9432             logStateAndMessage(message, getClass().getSimpleName());
9433 
9434             switch(message.what) {
9435                 case CMD_START_SUPPLICANT:
9436                 case CMD_STOP_SUPPLICANT:
9437                 case CMD_START_AP:
9438                 case CMD_STOP_AP:
9439                 case CMD_START_DRIVER:
9440                 case CMD_STOP_DRIVER:
9441                 case CMD_SET_OPERATIONAL_MODE:
9442                 case CMD_SET_COUNTRY_CODE:
9443                 case CMD_SET_FREQUENCY_BAND:
9444                 case CMD_START_PACKET_FILTERING:
9445                 case CMD_STOP_PACKET_FILTERING:
9446                 case CMD_TETHER_STATE_CHANGE:
9447                     deferMessage(message);
9448                     break;
9449                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
9450                     WifiConfiguration config = (WifiConfiguration) message.obj;
9451                     if (config != null) {
9452                         startSoftApWithConfig(config);
9453                     } else {
9454                         loge("Softap config is null!");
9455                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
9456                     }
9457                     break;
9458                 case CMD_START_AP_SUCCESS:
9459                     setWifiApState(WIFI_AP_STATE_ENABLED, 0);
9460                     transitionTo(mSoftApStartedState);
9461                     break;
9462                 case CMD_START_AP_FAILURE:
9463                     setWifiApState(WIFI_AP_STATE_FAILED, message.arg1);
9464                     transitionTo(mInitialState);
9465                     break;
9466                 default:
9467                     return NOT_HANDLED;
9468             }
9469             return HANDLED;
9470         }
9471     }
9472 
9473     class SoftApStartedState extends State {
9474         @Override
processMessage(Message message)9475         public boolean processMessage(Message message) {
9476             logStateAndMessage(message, getClass().getSimpleName());
9477 
9478             switch(message.what) {
9479                 case CMD_STOP_AP:
9480                     if (DBG) log("Stopping Soft AP");
9481                     /* We have not tethered at this point, so we just shutdown soft Ap */
9482                     try {
9483                         mNwService.stopAccessPoint(mInterfaceName);
9484                     } catch(Exception e) {
9485                         loge("Exception in stopAccessPoint()");
9486                     }
9487                     setWifiApState(WIFI_AP_STATE_DISABLED, 0);
9488                     transitionTo(mInitialState);
9489                     break;
9490                 case CMD_START_AP:
9491                     // Ignore a start on a running access point
9492                     break;
9493                     // Fail client mode operation when soft AP is enabled
9494                 case CMD_START_SUPPLICANT:
9495                     loge("Cannot start supplicant with a running soft AP");
9496                     setWifiState(WIFI_STATE_UNKNOWN);
9497                     break;
9498                 case CMD_TETHER_STATE_CHANGE:
9499                     TetherStateChange stateChange = (TetherStateChange) message.obj;
9500                     if (startTethering(stateChange.available)) {
9501                         transitionTo(mTetheringState);
9502                     }
9503                     break;
9504                 default:
9505                     return NOT_HANDLED;
9506             }
9507             return HANDLED;
9508         }
9509     }
9510 
9511     class TetheringState extends State {
9512         @Override
enter()9513         public void enter() {
9514             /* Send ourselves a delayed message to shut down if tethering fails to notify */
9515             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
9516                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
9517         }
9518         @Override
processMessage(Message message)9519         public boolean processMessage(Message message) {
9520             logStateAndMessage(message, getClass().getSimpleName());
9521 
9522             switch(message.what) {
9523                 case CMD_TETHER_STATE_CHANGE:
9524                     TetherStateChange stateChange = (TetherStateChange) message.obj;
9525                     if (isWifiTethered(stateChange.active)) {
9526                         transitionTo(mTetheredState);
9527                     }
9528                     return HANDLED;
9529                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
9530                     if (message.arg1 == mTetherToken) {
9531                         loge("Failed to get tether update, shutdown soft access point");
9532                         transitionTo(mSoftApStartedState);
9533                         // Needs to be first thing handled
9534                         sendMessageAtFrontOfQueue(CMD_STOP_AP);
9535                     }
9536                     break;
9537                 case CMD_START_SUPPLICANT:
9538                 case CMD_STOP_SUPPLICANT:
9539                 case CMD_START_AP:
9540                 case CMD_STOP_AP:
9541                 case CMD_START_DRIVER:
9542                 case CMD_STOP_DRIVER:
9543                 case CMD_SET_OPERATIONAL_MODE:
9544                 case CMD_SET_COUNTRY_CODE:
9545                 case CMD_SET_FREQUENCY_BAND:
9546                 case CMD_START_PACKET_FILTERING:
9547                 case CMD_STOP_PACKET_FILTERING:
9548                     deferMessage(message);
9549                     break;
9550                 default:
9551                     return NOT_HANDLED;
9552             }
9553             return HANDLED;
9554         }
9555     }
9556 
9557     class TetheredState extends State {
9558         @Override
processMessage(Message message)9559         public boolean processMessage(Message message) {
9560             logStateAndMessage(message, getClass().getSimpleName());
9561 
9562             switch(message.what) {
9563                 case CMD_TETHER_STATE_CHANGE:
9564                     TetherStateChange stateChange = (TetherStateChange) message.obj;
9565                     if (!isWifiTethered(stateChange.active)) {
9566                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
9567                         setHostApRunning(null, false);
9568                         setHostApRunning(null, true);
9569                     }
9570                     return HANDLED;
9571                 case CMD_STOP_AP:
9572                     if (DBG) log("Untethering before stopping AP");
9573                     setWifiApState(WIFI_AP_STATE_DISABLING, 0);
9574                     stopTethering();
9575                     transitionTo(mUntetheringState);
9576                     // More work to do after untethering
9577                     deferMessage(message);
9578                     break;
9579                 default:
9580                     return NOT_HANDLED;
9581             }
9582             return HANDLED;
9583         }
9584     }
9585 
9586     class UntetheringState extends State {
9587         @Override
enter()9588         public void enter() {
9589             /* Send ourselves a delayed message to shut down if tethering fails to notify */
9590             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
9591                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
9592 
9593         }
9594         @Override
processMessage(Message message)9595         public boolean processMessage(Message message) {
9596             logStateAndMessage(message, getClass().getSimpleName());
9597 
9598             switch(message.what) {
9599                 case CMD_TETHER_STATE_CHANGE:
9600                     TetherStateChange stateChange = (TetherStateChange) message.obj;
9601 
9602                     /* Wait till wifi is untethered */
9603                     if (isWifiTethered(stateChange.active)) break;
9604 
9605                     transitionTo(mSoftApStartedState);
9606                     break;
9607                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
9608                     if (message.arg1 == mTetherToken) {
9609                         loge("Failed to get tether update, force stop access point");
9610                         transitionTo(mSoftApStartedState);
9611                     }
9612                     break;
9613                 case CMD_START_SUPPLICANT:
9614                 case CMD_STOP_SUPPLICANT:
9615                 case CMD_START_AP:
9616                 case CMD_STOP_AP:
9617                 case CMD_START_DRIVER:
9618                 case CMD_STOP_DRIVER:
9619                 case CMD_SET_OPERATIONAL_MODE:
9620                 case CMD_SET_COUNTRY_CODE:
9621                 case CMD_SET_FREQUENCY_BAND:
9622                 case CMD_START_PACKET_FILTERING:
9623                 case CMD_STOP_PACKET_FILTERING:
9624                     deferMessage(message);
9625                     break;
9626                 default:
9627                     return NOT_HANDLED;
9628             }
9629             return HANDLED;
9630         }
9631     }
9632 
9633     /**
9634      * State machine initiated requests can have replyTo set to null indicating
9635      * there are no recepients, we ignore those reply actions.
9636      */
replyToMessage(Message msg, int what)9637     private void replyToMessage(Message msg, int what) {
9638         if (msg.replyTo == null) return;
9639         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9640         mReplyChannel.replyToMessage(msg, dstMsg);
9641     }
9642 
replyToMessage(Message msg, int what, int arg1)9643     private void replyToMessage(Message msg, int what, int arg1) {
9644         if (msg.replyTo == null) return;
9645         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9646         dstMsg.arg1 = arg1;
9647         mReplyChannel.replyToMessage(msg, dstMsg);
9648     }
9649 
replyToMessage(Message msg, int what, Object obj)9650     private void replyToMessage(Message msg, int what, Object obj) {
9651         if (msg.replyTo == null) return;
9652         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9653         dstMsg.obj = obj;
9654         mReplyChannel.replyToMessage(msg, dstMsg);
9655     }
9656 
9657     /**
9658      * arg2 on the source message has a unique id that needs to be retained in replies
9659      * to match the request
9660      * <p>see WifiManager for details
9661      */
obtainMessageWithWhatAndArg2(Message srcMsg, int what)9662     private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
9663         Message msg = Message.obtain();
9664         msg.what = what;
9665         msg.arg2 = srcMsg.arg2;
9666         return msg;
9667     }
9668 
9669     /**
9670      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
9671      * @param msg Must have a WifiConfiguration obj to succeed
9672      */
broadcastWifiCredentialChanged(int wifiCredentialEventType, WifiConfiguration config)9673     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
9674             WifiConfiguration config) {
9675         if (config != null && config.preSharedKey != null) {
9676             Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
9677             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
9678             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
9679                     wifiCredentialEventType);
9680             mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
9681                     android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
9682         }
9683     }
9684 
parseHex(char ch)9685     private static int parseHex(char ch) {
9686         if ('0' <= ch && ch <= '9') {
9687             return ch - '0';
9688         } else if ('a' <= ch && ch <= 'f') {
9689             return ch - 'a' + 10;
9690         } else if ('A' <= ch && ch <= 'F') {
9691             return ch - 'A' + 10;
9692         } else {
9693             throw new NumberFormatException("" + ch + " is not a valid hex digit");
9694         }
9695     }
9696 
parseHex(String hex)9697     private byte[] parseHex(String hex) {
9698         /* This only works for good input; don't throw bad data at it */
9699         if (hex == null) {
9700             return new byte[0];
9701         }
9702 
9703         if (hex.length() % 2 != 0) {
9704             throw new NumberFormatException(hex + " is not a valid hex string");
9705         }
9706 
9707         byte[] result = new byte[(hex.length())/2 + 1];
9708         result[0] = (byte) ((hex.length())/2);
9709         for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
9710             int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
9711             byte b = (byte) (val & 0xFF);
9712             result[j] = b;
9713         }
9714 
9715         return result;
9716     }
9717 
makeHex(byte[] bytes)9718     private static String makeHex(byte[] bytes) {
9719         StringBuilder sb = new StringBuilder();
9720         for (byte b : bytes) {
9721             sb.append(String.format("%02x", b));
9722         }
9723         return sb.toString();
9724     }
9725 
makeHex(byte[] bytes, int from, int len)9726     private static String makeHex(byte[] bytes, int from, int len) {
9727         StringBuilder sb = new StringBuilder();
9728         for (int i = 0; i < len; i++) {
9729             sb.append(String.format("%02x", bytes[from+i]));
9730         }
9731         return sb.toString();
9732     }
9733 
concat(byte[] array1, byte[] array2, byte[] array3)9734     private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
9735 
9736         int len = array1.length + array2.length + array3.length;
9737 
9738         if (array1.length != 0) {
9739             len++;                      /* add another byte for size */
9740         }
9741 
9742         if (array2.length != 0) {
9743             len++;                      /* add another byte for size */
9744         }
9745 
9746         if (array3.length != 0) {
9747             len++;                      /* add another byte for size */
9748         }
9749 
9750         byte[] result = new byte[len];
9751 
9752         int index = 0;
9753         if (array1.length != 0) {
9754             result[index] = (byte) (array1.length & 0xFF);
9755             index++;
9756             for (byte b : array1) {
9757                 result[index] = b;
9758                 index++;
9759             }
9760         }
9761 
9762         if (array2.length != 0) {
9763             result[index] = (byte) (array2.length & 0xFF);
9764             index++;
9765             for (byte b : array2) {
9766                 result[index] = b;
9767                 index++;
9768             }
9769         }
9770 
9771         if (array3.length != 0) {
9772             result[index] = (byte) (array3.length & 0xFF);
9773             index++;
9774             for (byte b : array3) {
9775                 result[index] = b;
9776                 index++;
9777             }
9778         }
9779         return result;
9780     }
9781 
concatHex(byte[] array1, byte[] array2)9782     private static byte[] concatHex(byte[] array1, byte[] array2) {
9783 
9784         int len = array1.length + array2.length;
9785 
9786         byte[] result = new byte[len];
9787 
9788         int index = 0;
9789         if (array1.length != 0) {
9790             for (byte b : array1) {
9791                 result[index] = b;
9792                 index++;
9793             }
9794         }
9795 
9796         if (array2.length != 0) {
9797             for (byte b : array2) {
9798                 result[index] = b;
9799                 index++;
9800             }
9801         }
9802 
9803         return result;
9804     }
9805 
handleGsmAuthRequest(SimAuthRequestData requestData)9806     void handleGsmAuthRequest(SimAuthRequestData requestData) {
9807         if (targetWificonfiguration == null
9808                 || targetWificonfiguration.networkId == requestData.networkId) {
9809             logd("id matches targetWifiConfiguration");
9810         } else {
9811             logd("id does not match targetWifiConfiguration");
9812             return;
9813         }
9814 
9815         TelephonyManager tm = (TelephonyManager)
9816                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
9817 
9818         if (tm != null) {
9819             StringBuilder sb = new StringBuilder();
9820             for (String challenge : requestData.data) {
9821 
9822                 if (challenge == null || challenge.isEmpty())
9823                     continue;
9824                 logd("RAND = " + challenge);
9825 
9826                 byte[] rand = null;
9827                 try {
9828                     rand = parseHex(challenge);
9829                 } catch (NumberFormatException e) {
9830                     loge("malformed challenge");
9831                     continue;
9832                 }
9833 
9834                 String base64Challenge = android.util.Base64.encodeToString(
9835                         rand, android.util.Base64.NO_WRAP);
9836                 /*
9837                  * First, try with appType = 2 => USIM according to
9838                  * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
9839                  */
9840                 int appType = 2;
9841                 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9842                 if (tmResponse == null) {
9843                     /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
9844                      * appType = 1 => SIM
9845                      */
9846                     appType = 1;
9847                     tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9848                 }
9849                 logv("Raw Response - " + tmResponse);
9850 
9851                 if (tmResponse != null && tmResponse.length() > 4) {
9852                     byte[] result = android.util.Base64.decode(tmResponse,
9853                             android.util.Base64.DEFAULT);
9854                     logv("Hex Response -" + makeHex(result));
9855                     int sres_len = result[0];
9856                     String sres = makeHex(result, 1, sres_len);
9857                     int kc_offset = 1+sres_len;
9858                     int kc_len = result[kc_offset];
9859                     String kc = makeHex(result, 1+kc_offset, kc_len);
9860                     sb.append(":" + kc + ":" + sres);
9861                     logv("kc:" + kc + " sres:" + sres);
9862                 } else {
9863                     loge("bad response - " + tmResponse);
9864                 }
9865             }
9866 
9867             String response = sb.toString();
9868             logv("Supplicant Response -" + response);
9869             mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
9870         } else {
9871             loge("could not get telephony manager");
9872         }
9873     }
9874 
handle3GAuthRequest(SimAuthRequestData requestData)9875     void handle3GAuthRequest(SimAuthRequestData requestData) {
9876         StringBuilder sb = new StringBuilder();
9877         byte[] rand = null;
9878         byte[] authn = null;
9879         String res_type = "UMTS-AUTH";
9880 
9881         if (targetWificonfiguration == null
9882                 || targetWificonfiguration.networkId == requestData.networkId) {
9883             logd("id matches targetWifiConfiguration");
9884         } else {
9885             logd("id does not match targetWifiConfiguration");
9886             return;
9887         }
9888         if (requestData.data.length == 2) {
9889             try {
9890                 rand = parseHex(requestData.data[0]);
9891                 authn = parseHex(requestData.data[1]);
9892             } catch (NumberFormatException e) {
9893                 loge("malformed challenge");
9894             }
9895         } else {
9896                loge("malformed challenge");
9897         }
9898 
9899         String tmResponse = "";
9900         if (rand != null && authn != null) {
9901             String base64Challenge = android.util.Base64.encodeToString(
9902                     concatHex(rand,authn), android.util.Base64.NO_WRAP);
9903 
9904             TelephonyManager tm = (TelephonyManager)
9905                     mContext.getSystemService(Context.TELEPHONY_SERVICE);
9906             if (tm != null) {
9907                 int appType = 2; // 2 => USIM
9908                 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9909                 logv("Raw Response - " + tmResponse);
9910             } else {
9911                 loge("could not get telephony manager");
9912             }
9913         }
9914 
9915         if (tmResponse != null && tmResponse.length() > 4) {
9916             byte[] result = android.util.Base64.decode(tmResponse,
9917                     android.util.Base64.DEFAULT);
9918             loge("Hex Response - " + makeHex(result));
9919             byte tag = result[0];
9920             if (tag == (byte) 0xdb) {
9921                 logv("successful 3G authentication ");
9922                 int res_len = result[1];
9923                 String res = makeHex(result, 2, res_len);
9924                 int ck_len = result[res_len + 2];
9925                 String ck = makeHex(result, res_len + 3, ck_len);
9926                 int ik_len = result[res_len + ck_len + 3];
9927                 String ik = makeHex(result, res_len + ck_len + 4, ik_len);
9928                 sb.append(":" + ik + ":" + ck + ":" + res);
9929                 logv("ik:" + ik + "ck:" + ck + " res:" + res);
9930             } else if (tag == (byte) 0xdc) {
9931                 loge("synchronisation failure");
9932                 int auts_len = result[1];
9933                 String auts = makeHex(result, 2, auts_len);
9934                 res_type = "UMTS-AUTS";
9935                 sb.append(":" + auts);
9936                 logv("auts:" + auts);
9937             } else {
9938                 loge("bad response - unknown tag = " + tag);
9939                 return;
9940             }
9941         } else {
9942             loge("bad response - " + tmResponse);
9943             return;
9944         }
9945 
9946         String response = sb.toString();
9947         logv("Supplicant Response -" + response);
9948         mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
9949     }
9950 
9951     /**
9952      * @param reason reason code from supplicant on network disconnected event
9953      * @return true if this is a suspicious disconnect
9954      */
unexpectedDisconnectedReason(int reason)9955     static boolean unexpectedDisconnectedReason(int reason) {
9956         return reason == 2              // PREV_AUTH_NOT_VALID
9957                 || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
9958                 || reason == 7          // FRAME_FROM_NONASSOC_STA
9959                 || reason == 8          // STA_HAS_LEFT
9960                 || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
9961                 || reason == 14         // MICHAEL_MIC_FAILURE
9962                 || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
9963                 || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
9964                 || reason == 18         // GROUP_CIPHER_NOT_VALID
9965                 || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
9966                 || reason == 23         // IEEE_802_1X_AUTH_FAILED
9967                 || reason == 34;        // DISASSOC_LOW_ACK
9968     }
9969 }
9970