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