• 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 android.net.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.NetworkInfo;
52 import android.net.NetworkInfo.DetailedState;
53 import android.net.NetworkUtils;
54 import android.net.RouteInfo;
55 import android.net.wifi.WpsResult.Status;
56 import android.net.wifi.p2p.WifiP2pManager;
57 import android.net.wifi.p2p.WifiP2pService;
58 import android.os.BatteryStats;
59 import android.os.Binder;
60 import android.os.Bundle;
61 import android.os.IBinder;
62 import android.os.INetworkManagementService;
63 import android.os.Message;
64 import android.os.Messenger;
65 import android.os.PowerManager;
66 import android.os.Process;
67 import android.os.RemoteException;
68 import android.os.ServiceManager;
69 import android.os.SystemClock;
70 import android.os.SystemProperties;
71 import android.os.UserHandle;
72 import android.os.WorkSource;
73 import android.provider.Settings;
74 import android.util.Log;
75 import android.util.LruCache;
76 import android.text.TextUtils;
77 
78 import com.android.internal.R;
79 import com.android.internal.app.IBatteryStats;
80 import com.android.internal.util.AsyncChannel;
81 import com.android.internal.util.Protocol;
82 import com.android.internal.util.State;
83 import com.android.internal.util.StateMachine;
84 
85 import com.android.server.net.BaseNetworkObserver;
86 
87 import java.io.FileDescriptor;
88 import java.io.PrintWriter;
89 import java.net.InetAddress;
90 import java.net.Inet6Address;
91 import java.util.ArrayList;
92 import java.util.List;
93 import java.util.Locale;
94 import java.util.concurrent.atomic.AtomicInteger;
95 import java.util.concurrent.atomic.AtomicBoolean;
96 import java.util.Iterator;
97 import java.util.regex.Pattern;
98 
99 /**
100  * Track the state of Wifi connectivity. All event handling is done here,
101  * and all changes in connectivity state are initiated here.
102  *
103  * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
104  * In the current implementation, we support concurrent wifi p2p and wifi operation.
105  * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
106  * handles p2p operation.
107  *
108  * @hide
109  */
110 public class WifiStateMachine extends StateMachine {
111 
112     private static final String NETWORKTYPE = "WIFI";
113     private static final boolean DBG = false;
114 
115     private WifiMonitor mWifiMonitor;
116     private WifiNative mWifiNative;
117     private WifiConfigStore mWifiConfigStore;
118     private INetworkManagementService mNwService;
119     private ConnectivityManager mCm;
120 
121     private final boolean mP2pSupported;
122     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
123     private boolean mTemporarilyDisconnectWifi = false;
124     private final String mPrimaryDeviceType;
125 
126     /* Scan results handling */
127     private List<ScanResult> mScanResults = new ArrayList<ScanResult>();
128     private static final Pattern scanResultPattern = Pattern.compile("\t+");
129     private static final int SCAN_RESULT_CACHE_SIZE = 80;
130     private final LruCache<String, ScanResult> mScanResultCache;
131 
132     /* Batch scan results */
133     private final List<BatchedScanResult> mBatchedScanResults =
134             new ArrayList<BatchedScanResult>();
135     private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
136     private int mExpectedBatchedScans = 0;
137     private long mBatchedScanMinPollTime = 0;
138 
139     /* Chipset supports background scan */
140     private final boolean mBackgroundScanSupported;
141 
142     private String mInterfaceName;
143     /* Tethering interface could be separate from wlan interface */
144     private String mTetherInterfaceName;
145 
146     private int mLastSignalLevel = -1;
147     private String mLastBssid;
148     private int mLastNetworkId;
149     private boolean mEnableRssiPolling = false;
150     private boolean mEnableBackgroundScan = false;
151     private int mRssiPollToken = 0;
152     private int mReconnectCount = 0;
153     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
154     * In CONNECT_MODE, the STA can scan and connect to an access point
155     * In SCAN_ONLY_MODE, the STA can only scan for access points
156     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
157     */
158     private int mOperationalMode = CONNECT_MODE;
159     private boolean mScanResultIsPending = false;
160     private WorkSource mScanWorkSource = null;
161     private static final int UNKNOWN_SCAN_SOURCE = -1;
162     /* Tracks if state machine has received any screen state change broadcast yet.
163      * We can miss one of these at boot.
164      */
165     private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false);
166 
167     private boolean mBluetoothConnectionActive = false;
168 
169     private PowerManager.WakeLock mSuspendWakeLock;
170 
171     /**
172      * Interval in milliseconds between polling for RSSI
173      * and linkspeed information
174      */
175     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
176 
177     /**
178      * Delay between supplicant restarts upon failure to establish connection
179      */
180     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
181 
182     /**
183      * Number of times we attempt to restart supplicant
184      */
185     private static final int SUPPLICANT_RESTART_TRIES = 5;
186 
187     private int mSupplicantRestartCount = 0;
188     /* Tracks sequence number on stop failure message */
189     private int mSupplicantStopFailureToken = 0;
190 
191     /**
192      * Tether state change notification time out
193      */
194     private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
195 
196     /* Tracks sequence number on a tether notification time out */
197     private int mTetherToken = 0;
198 
199     /**
200      * Driver start time out.
201      */
202     private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
203 
204     /* Tracks sequence number on a driver time out */
205     private int mDriverStartToken = 0;
206 
207     /**
208      * The link properties of the wifi interface.
209      * Do not modify this directly; use updateLinkProperties instead.
210      */
211     private LinkProperties mLinkProperties;
212 
213     /**
214      * Subset of link properties coming from netlink.
215      * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
216      * and domains obtained from router advertisements (RFC 6106).
217      */
218     private final LinkProperties mNetlinkLinkProperties;
219 
220     /* Tracks sequence number on a periodic scan message */
221     private int mPeriodicScanToken = 0;
222 
223     // Wakelock held during wifi start/stop and driver load/unload
224     private PowerManager.WakeLock mWakeLock;
225 
226     private Context mContext;
227 
228     private final Object mDhcpResultsLock = new Object();
229     private DhcpResults mDhcpResults;
230     private WifiInfo mWifiInfo;
231     private NetworkInfo mNetworkInfo;
232     private SupplicantStateTracker mSupplicantStateTracker;
233     private DhcpStateMachine mDhcpStateMachine;
234     private boolean mDhcpActive = false;
235 
236     private final AtomicInteger mCountryCodeSequence = new AtomicInteger();
237 
238     private class InterfaceObserver extends BaseNetworkObserver {
239         private WifiStateMachine mWifiStateMachine;
240 
InterfaceObserver(WifiStateMachine wifiStateMachine)241         InterfaceObserver(WifiStateMachine wifiStateMachine) {
242             super();
243             mWifiStateMachine = wifiStateMachine;
244         }
245 
246         @Override
addressUpdated(String address, String iface, int flags, int scope)247         public void addressUpdated(String address, String iface, int flags, int scope) {
248             if (mWifiStateMachine.mInterfaceName.equals(iface)) {
249                 if (DBG) {
250                     log("addressUpdated: " + address + " on " + iface +
251                         " flags " + flags + " scope " + scope);
252                 }
253                 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, new LinkAddress(address));
254             }
255         }
256 
257         @Override
addressRemoved(String address, String iface, int flags, int scope)258         public void addressRemoved(String address, String iface, int flags, int scope) {
259             if (mWifiStateMachine.mInterfaceName.equals(iface)) {
260                 if (DBG) {
261                     log("addressRemoved: " + address + " on " + iface +
262                         " flags " + flags + " scope " + scope);
263                 }
264                 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, new LinkAddress(address));
265             }
266         }
267     }
268 
269     private InterfaceObserver mInterfaceObserver;
270 
271     private AlarmManager mAlarmManager;
272     private PendingIntent mScanIntent;
273     private PendingIntent mDriverStopIntent;
274     private PendingIntent mBatchedScanIntervalIntent;
275 
276     /* Tracks current frequency mode */
277     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
278 
279     /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
280     private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
281 
282     // Channel for sending replies.
283     private AsyncChannel mReplyChannel = new AsyncChannel();
284 
285     private WifiP2pManager mWifiP2pManager;
286     //Used to initiate a connection with WifiP2pService
287     private AsyncChannel mWifiP2pChannel;
288     private AsyncChannel mWifiApConfigChannel;
289 
290     /* The base for wifi message types */
291     static final int BASE = Protocol.BASE_WIFI;
292     /* Start the supplicant */
293     static final int CMD_START_SUPPLICANT                 = BASE + 11;
294     /* Stop the supplicant */
295     static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
296     /* Start the driver */
297     static final int CMD_START_DRIVER                     = BASE + 13;
298     /* Stop the driver */
299     static final int CMD_STOP_DRIVER                      = BASE + 14;
300     /* Indicates Static IP succeeded */
301     static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
302     /* Indicates Static IP failed */
303     static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
304     /* Indicates supplicant stop failed */
305     static final int CMD_STOP_SUPPLICANT_FAILED           = BASE + 17;
306     /* Delayed stop to avoid shutting down driver too quick*/
307     static final int CMD_DELAYED_STOP_DRIVER              = BASE + 18;
308     /* A delayed message sent to start driver when it fail to come up */
309     static final int CMD_DRIVER_START_TIMED_OUT           = BASE + 19;
310     /* Ready to switch to network as default */
311     static final int CMD_CAPTIVE_CHECK_COMPLETE           = BASE + 20;
312 
313     /* Start the soft access point */
314     static final int CMD_START_AP                         = BASE + 21;
315     /* Indicates soft ap start succeeded */
316     static final int CMD_START_AP_SUCCESS                 = BASE + 22;
317     /* Indicates soft ap start failed */
318     static final int CMD_START_AP_FAILURE                 = BASE + 23;
319     /* Stop the soft access point */
320     static final int CMD_STOP_AP                          = BASE + 24;
321     /* Set the soft access point configuration */
322     static final int CMD_SET_AP_CONFIG                    = BASE + 25;
323     /* Soft access point configuration set completed */
324     static final int CMD_SET_AP_CONFIG_COMPLETED          = BASE + 26;
325     /* Request the soft access point configuration */
326     static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
327     /* Response to access point configuration request */
328     static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
329     /* Invoked when getting a tether state change notification */
330     static final int CMD_TETHER_STATE_CHANGE              = BASE + 29;
331     /* A delayed message sent to indicate tether state change failed to arrive */
332     static final int CMD_TETHER_NOTIFICATION_TIMED_OUT    = BASE + 30;
333 
334     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 31;
335 
336     /* Supplicant commands */
337     /* Is supplicant alive ? */
338     static final int CMD_PING_SUPPLICANT                  = BASE + 51;
339     /* Add/update a network configuration */
340     static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
341     /* Delete a network */
342     static final int CMD_REMOVE_NETWORK                   = BASE + 53;
343     /* Enable a network. The device will attempt a connection to the given network. */
344     static final int CMD_ENABLE_NETWORK                   = BASE + 54;
345     /* Enable all networks */
346     static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
347     /* Blacklist network. De-prioritizes the given BSSID for connection. */
348     static final int CMD_BLACKLIST_NETWORK                = BASE + 56;
349     /* Clear the blacklist network list */
350     static final int CMD_CLEAR_BLACKLIST                  = BASE + 57;
351     /* Save configuration */
352     static final int CMD_SAVE_CONFIG                      = BASE + 58;
353     /* Get configured networks*/
354     static final int CMD_GET_CONFIGURED_NETWORKS          = BASE + 59;
355 
356     /* Supplicant commands after driver start*/
357     /* Initiate a scan */
358     static final int CMD_START_SCAN                       = BASE + 71;
359     /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
360     static final int CMD_SET_OPERATIONAL_MODE             = BASE + 72;
361     /* Disconnect from a network */
362     static final int CMD_DISCONNECT                       = BASE + 73;
363     /* Reconnect to a network */
364     static final int CMD_RECONNECT                        = BASE + 74;
365     /* Reassociate to a network */
366     static final int CMD_REASSOCIATE                      = BASE + 75;
367     /* Controls suspend mode optimizations
368      *
369      * When high perf mode is enabled, suspend mode optimizations are disabled
370      *
371      * When high perf mode is disabled, suspend mode optimizations are enabled
372      *
373      * Suspend mode optimizations include:
374      * - packet filtering
375      * - turn off roaming
376      * - DTIM wake up settings
377      */
378     static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
379     /* Set the country code */
380     static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
381     /* Enables RSSI poll */
382     static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
383     /* RSSI poll */
384     static final int CMD_RSSI_POLL                        = BASE + 83;
385     /* Set up packet filtering */
386     static final int CMD_START_PACKET_FILTERING           = BASE + 84;
387     /* Clear packet filter */
388     static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
389     /* Enable suspend mode optimizations in the driver */
390     static final int CMD_SET_SUSPEND_OPT_ENABLED          = BASE + 86;
391     /* When there are no saved networks, we do a periodic scan to notify user of
392      * an open network */
393     static final int CMD_NO_NETWORKS_PERIODIC_SCAN        = BASE + 88;
394 
395     /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
396     static final int MULTICAST_V6  = 1;
397     static final int MULTICAST_V4  = 0;
398 
399    /* Set the frequency band */
400     static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
401     /* Enable background scan for configured networks */
402     static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
403     /* Enable TDLS on a specific MAC address */
404     static final int CMD_ENABLE_TDLS                      = BASE + 92;
405 
406     /* Commands from/to the SupplicantStateTracker */
407     /* Reset the supplicant state tracker */
408     static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
409 
410     /* P2p commands */
411     /* We are ok with no response here since we wont do much with it anyway */
412     public static final int CMD_ENABLE_P2P                = BASE + 131;
413     /* In order to shut down supplicant cleanly, we wait till p2p has
414      * been disabled */
415     public static final int CMD_DISABLE_P2P_REQ           = BASE + 132;
416     public static final int CMD_DISABLE_P2P_RSP           = BASE + 133;
417 
418     public static final int CMD_BOOT_COMPLETED            = BASE + 134;
419 
420     /* change the batch scan settings.
421      * arg1 = responsible UID
422      * arg2 = csph (channel scans per hour)
423      * obj = bundle with the new settings and the optional worksource
424      */
425     public static final int CMD_SET_BATCHED_SCAN          = BASE + 135;
426     public static final int CMD_START_NEXT_BATCHED_SCAN   = BASE + 136;
427     public static final int CMD_POLL_BATCHED_SCAN         = BASE + 137;
428 
429     /* Link configuration (IP address, DNS, ...) changes */
430     /* An new IP address was added to our interface, or an existing IP address was updated */
431     static final int CMD_IP_ADDRESS_UPDATED               = BASE + 140;
432     /* An IP address was removed from our interface */
433     static final int CMD_IP_ADDRESS_REMOVED               = BASE + 141;
434     /* Reload all networks and reconnect */
435     static final int CMD_RELOAD_TLS_AND_RECONNECT         = BASE + 142;
436 
437     /* Wifi state machine modes of operation */
438     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
439     public static final int CONNECT_MODE                   = 1;
440     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
441     public static final int SCAN_ONLY_MODE                 = 2;
442     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
443     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE   = 3;
444 
445     private static final int SUCCESS = 1;
446     private static final int FAILURE = -1;
447 
448     /**
449      * The maximum number of times we will retry a connection to an access point
450      * for which we have failed in acquiring an IP address from DHCP. A value of
451      * N means that we will make N+1 connection attempts in all.
452      * <p>
453      * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
454      * value if a Settings value is not present.
455      */
456     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
457 
458     /* Tracks if suspend optimizations need to be disabled by DHCP,
459      * screen or due to high perf mode.
460      * When any of them needs to disable it, we keep the suspend optimizations
461      * disabled
462      */
463     private int mSuspendOptNeedsDisabled = 0;
464 
465     private static final int SUSPEND_DUE_TO_DHCP       = 1;
466     private static final int SUSPEND_DUE_TO_HIGH_PERF  = 1<<1;
467     private static final int SUSPEND_DUE_TO_SCREEN     = 1<<2;
468 
469     /* Tracks if user has enabled suspend optimizations through settings */
470     private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
471 
472     /**
473      * Default framework scan interval in milliseconds. This is used in the scenario in which
474      * wifi chipset does not support background scanning to set up a
475      * periodic wake up scan so that the device can connect to a new access
476      * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
477      * override this.
478      */
479     private final int mDefaultFrameworkScanIntervalMs;
480 
481     /**
482      * Supplicant scan interval in milliseconds.
483      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
484      * from the default config if the setting is not set
485      */
486     private long mSupplicantScanIntervalMs;
487 
488     /**
489      * Minimum time interval between enabling all networks.
490      * A device can end up repeatedly connecting to a bad network on screen on/off toggle
491      * due to enabling every time. We add a threshold to avoid this.
492      */
493     private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
494     private long mLastEnableAllNetworksTime;
495 
496     /**
497      * Starting and shutting down driver too quick causes problems leading to driver
498      * being in a bad state. Delay driver stop.
499      */
500     private final int mDriverStopDelayMs;
501     private int mDelayedStopCounter;
502     private boolean mInDelayedStop = false;
503 
504     // sometimes telephony gives us this data before boot is complete and we can't store it
505     // until after, so the write is deferred
506     private volatile String mPersistedCountryCode;
507 
508     // Supplicant doesn't like setting the same country code multiple times (it may drop
509     // currently connected network), so we save the country code here to avoid redundency
510     private String mLastSetCountryCode;
511 
512     private static final int MIN_RSSI = -200;
513     private static final int MAX_RSSI = 256;
514 
515     /* Default parent state */
516     private State mDefaultState = new DefaultState();
517     /* Temporary initial state */
518     private State mInitialState = new InitialState();
519     /* Driver loaded, waiting for supplicant to start */
520     private State mSupplicantStartingState = new SupplicantStartingState();
521     /* Driver loaded and supplicant ready */
522     private State mSupplicantStartedState = new SupplicantStartedState();
523     /* Waiting for supplicant to stop and monitor to exit */
524     private State mSupplicantStoppingState = new SupplicantStoppingState();
525     /* Driver start issued, waiting for completed event */
526     private State mDriverStartingState = new DriverStartingState();
527     /* Driver started */
528     private State mDriverStartedState = new DriverStartedState();
529     /* Wait until p2p is disabled
530      * This is a special state which is entered right after we exit out of DriverStartedState
531      * before transitioning to another state.
532      */
533     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
534     /* Driver stopping */
535     private State mDriverStoppingState = new DriverStoppingState();
536     /* Driver stopped */
537     private State mDriverStoppedState = new DriverStoppedState();
538     /* Scan for networks, no connection will be established */
539     private State mScanModeState = new ScanModeState();
540     /* Connecting to an access point */
541     private State mConnectModeState = new ConnectModeState();
542     /* Connected at 802.11 (L2) level */
543     private State mL2ConnectedState = new L2ConnectedState();
544     /* fetching IP after connection to access point (assoc+auth complete) */
545     private State mObtainingIpState = new ObtainingIpState();
546     /* Waiting for link quality verification to be complete */
547     private State mVerifyingLinkState = new VerifyingLinkState();
548     /* Waiting for captive portal check to be complete */
549     private State mCaptivePortalCheckState = new CaptivePortalCheckState();
550     /* Connected with IP addr */
551     private State mConnectedState = new ConnectedState();
552     /* disconnect issued, waiting for network disconnect confirmation */
553     private State mDisconnectingState = new DisconnectingState();
554     /* Network is not connected, supplicant assoc+auth is not complete */
555     private State mDisconnectedState = new DisconnectedState();
556     /* Waiting for WPS to be completed*/
557     private State mWpsRunningState = new WpsRunningState();
558 
559     /* Soft ap is starting up */
560     private State mSoftApStartingState = new SoftApStartingState();
561     /* Soft ap is running */
562     private State mSoftApStartedState = new SoftApStartedState();
563     /* Soft ap is running and we are waiting for tether notification */
564     private State mTetheringState = new TetheringState();
565     /* Soft ap is running and we are tethered through connectivity service */
566     private State mTetheredState = new TetheredState();
567     /* Waiting for untether confirmation before stopping soft Ap */
568     private State mUntetheringState = new UntetheringState();
569 
570     private class TetherStateChange {
571         ArrayList<String> available;
572         ArrayList<String> active;
TetherStateChange(ArrayList<String> av, ArrayList<String> ac)573         TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
574             available = av;
575             active = ac;
576         }
577     }
578 
579 
580     /**
581      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
582      *         {@link WifiManager#WIFI_STATE_DISABLING},
583      *         {@link WifiManager#WIFI_STATE_ENABLED},
584      *         {@link WifiManager#WIFI_STATE_ENABLING},
585      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
586      *
587      */
588     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
589 
590     /**
591      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
592      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
593      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
594      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
595      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
596      *
597      */
598     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
599 
600     private static final int SCAN_REQUEST = 0;
601     private static final String ACTION_START_SCAN =
602         "com.android.server.WifiManager.action.START_SCAN";
603 
604     private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
605     private static final int DRIVER_STOP_REQUEST = 0;
606     private static final String ACTION_DELAYED_DRIVER_STOP =
607         "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
608 
609     private static final String ACTION_REFRESH_BATCHED_SCAN =
610             "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN";
611     /**
612      * Keep track of whether WIFI is running.
613      */
614     private boolean mIsRunning = false;
615 
616     /**
617      * Keep track of whether we last told the battery stats we had started.
618      */
619     private boolean mReportedRunning = false;
620 
621     /**
622      * Most recently set source of starting WIFI.
623      */
624     private final WorkSource mRunningWifiUids = new WorkSource();
625 
626     /**
627      * The last reported UIDs that were responsible for starting WIFI.
628      */
629     private final WorkSource mLastRunningWifiUids = new WorkSource();
630 
631     private final IBatteryStats mBatteryStats;
632 
633     private BatchedScanSettings mBatchedScanSettings = null;
634 
635     /**
636      * Track the worksource/cost of the current settings and track what's been noted
637      * to the battery stats, so we can mark the end of the previous when changing.
638      */
639     private WorkSource mBatchedScanWorkSource = null;
640     private int mBatchedScanCsph = 0;
641     private WorkSource mNotedBatchedScanWorkSource = null;
642     private int mNotedBatchedScanCsph = 0;
643 
644 
WifiStateMachine(Context context, String wlanInterface)645     public WifiStateMachine(Context context, String wlanInterface) {
646         super("WifiStateMachine");
647         mContext = context;
648         mInterfaceName = wlanInterface;
649 
650         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
651         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
652                 BatteryStats.SERVICE_NAME));
653 
654         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
655         mNwService = INetworkManagementService.Stub.asInterface(b);
656 
657         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
658                 PackageManager.FEATURE_WIFI_DIRECT);
659 
660         mWifiNative = new WifiNative(mInterfaceName);
661         mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
662         mWifiMonitor = new WifiMonitor(this, mWifiNative);
663         mWifiInfo = new WifiInfo();
664         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
665                 getHandler());
666         mLinkProperties = new LinkProperties();
667         mNetlinkLinkProperties = new LinkProperties();
668 
669         mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
670 
671         mNetworkInfo.setIsAvailable(false);
672         mLastBssid = null;
673         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
674         mLastSignalLevel = -1;
675 
676         mInterfaceObserver = new InterfaceObserver(this);
677         try {
678             mNwService.registerObserver(mInterfaceObserver);
679         } catch (RemoteException e) {
680             loge("Couldn't register interface observer: " + e.toString());
681         }
682 
683         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
684         Intent scanIntent = new Intent(ACTION_START_SCAN, null);
685         mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
686 
687         Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
688         mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0);
689 
690         mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
691                 R.integer.config_wifi_framework_scan_interval);
692 
693         mDriverStopDelayMs = mContext.getResources().getInteger(
694                 R.integer.config_wifi_driver_stop_delay);
695 
696         mBackgroundScanSupported = mContext.getResources().getBoolean(
697                 R.bool.config_wifi_background_scan_support);
698 
699         mPrimaryDeviceType = mContext.getResources().getString(
700                 R.string.config_wifi_p2p_device_type);
701 
702         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
703                     Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
704 
705         mContext.registerReceiver(
706             new BroadcastReceiver() {
707                 @Override
708                 public void onReceive(Context context, Intent intent) {
709                     ArrayList<String> available = intent.getStringArrayListExtra(
710                             ConnectivityManager.EXTRA_AVAILABLE_TETHER);
711                     ArrayList<String> active = intent.getStringArrayListExtra(
712                             ConnectivityManager.EXTRA_ACTIVE_TETHER);
713                     sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
714                 }
715             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
716 
717         mContext.registerReceiver(
718                 new BroadcastReceiver() {
719                     @Override
720                     public void onReceive(Context context, Intent intent) {
721                         final WorkSource workSource = null;
722                         startScan(UNKNOWN_SCAN_SOURCE, workSource);
723                     }
724                 },
725                 new IntentFilter(ACTION_START_SCAN));
726 
727         IntentFilter filter = new IntentFilter();
728         filter.addAction(Intent.ACTION_SCREEN_ON);
729         filter.addAction(Intent.ACTION_SCREEN_OFF);
730         filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
731         mContext.registerReceiver(
732                 new BroadcastReceiver() {
733                     @Override
734                     public void onReceive(Context context, Intent intent) {
735                         String action = intent.getAction();
736 
737                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
738                             handleScreenStateChanged(true);
739                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
740                             handleScreenStateChanged(false);
741                         } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
742                             startNextBatchedScanAsync();
743                         }
744                     }
745                 }, filter);
746 
747         mContext.registerReceiver(
748                 new BroadcastReceiver() {
749                     @Override
750                     public void onReceive(Context context, Intent intent) {
751                        int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
752                        sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
753                     }
754                 },
755                 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
756 
757         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
758                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
759                 new ContentObserver(getHandler()) {
760                     @Override
761                     public void onChange(boolean selfChange) {
762                         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
763                                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
764                     }
765                 });
766 
767         mContext.registerReceiver(
768                 new BroadcastReceiver() {
769                     @Override
770                     public void onReceive(Context context, Intent intent) {
771                         sendMessage(CMD_BOOT_COMPLETED);
772                     }
773                 },
774                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
775 
776         mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
777 
778         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
779         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
780 
781         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
782         mSuspendWakeLock.setReferenceCounted(false);
783 
784         addState(mDefaultState);
785             addState(mInitialState, mDefaultState);
786             addState(mSupplicantStartingState, mDefaultState);
787             addState(mSupplicantStartedState, mDefaultState);
788                 addState(mDriverStartingState, mSupplicantStartedState);
789                 addState(mDriverStartedState, mSupplicantStartedState);
790                     addState(mScanModeState, mDriverStartedState);
791                     addState(mConnectModeState, mDriverStartedState);
792                         addState(mL2ConnectedState, mConnectModeState);
793                             addState(mObtainingIpState, mL2ConnectedState);
794                             addState(mVerifyingLinkState, mL2ConnectedState);
795                             addState(mCaptivePortalCheckState, mL2ConnectedState);
796                             addState(mConnectedState, mL2ConnectedState);
797                         addState(mDisconnectingState, mConnectModeState);
798                         addState(mDisconnectedState, mConnectModeState);
799                         addState(mWpsRunningState, mConnectModeState);
800                 addState(mWaitForP2pDisableState, mSupplicantStartedState);
801                 addState(mDriverStoppingState, mSupplicantStartedState);
802                 addState(mDriverStoppedState, mSupplicantStartedState);
803             addState(mSupplicantStoppingState, mDefaultState);
804             addState(mSoftApStartingState, mDefaultState);
805             addState(mSoftApStartedState, mDefaultState);
806                 addState(mTetheringState, mSoftApStartedState);
807                 addState(mTetheredState, mSoftApStartedState);
808                 addState(mUntetheringState, mSoftApStartedState);
809 
810         setInitialState(mInitialState);
811 
812         setLogRecSize(2000);
813         setLogOnlyTransitions(false);
814         if (DBG) setDbg(true);
815 
816         //start the state machine
817         start();
818 
819         final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
820         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
821         intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
822         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
823     }
824 
825     /*********************************************************
826      * Methods exposed for public use
827      ********************************************************/
828 
getMessenger()829     public Messenger getMessenger() {
830         return new Messenger(getHandler());
831     }
832     /**
833      * TODO: doc
834      */
syncPingSupplicant(AsyncChannel channel)835     public boolean syncPingSupplicant(AsyncChannel channel) {
836         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
837         boolean result = (resultMsg.arg1 != FAILURE);
838         resultMsg.recycle();
839         return result;
840     }
841 
842     /**
843      * Initiate a wifi scan.  If workSource is not null, blame is given to it,
844      * otherwise blame is given to callingUid.
845      *
846      * @param callingUid The uid initiating the wifi scan.  Blame will be given
847      *                   here unless workSource is specified.
848      * @param workSource If not null, blame is given to workSource.
849      */
startScan(int callingUid, WorkSource workSource)850     public void startScan(int callingUid, WorkSource workSource) {
851         sendMessage(CMD_START_SCAN, callingUid, 0, workSource);
852     }
853 
854     /**
855      * start or stop batched scanning using the given settings
856      */
857     private static final String BATCHED_SETTING = "batched_settings";
858     private static final String BATCHED_WORKSOURCE = "batched_worksource";
setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, WorkSource workSource)859     public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph,
860             WorkSource workSource) {
861         Bundle bundle = new Bundle();
862         bundle.putParcelable(BATCHED_SETTING, settings);
863         bundle.putParcelable(BATCHED_WORKSOURCE, workSource);
864         sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle);
865     }
866 
syncGetBatchedScanResultsList()867     public List<BatchedScanResult> syncGetBatchedScanResultsList() {
868         synchronized (mBatchedScanResults) {
869             List<BatchedScanResult> batchedScanList =
870                     new ArrayList<BatchedScanResult>(mBatchedScanResults.size());
871             for(BatchedScanResult result: mBatchedScanResults) {
872                 batchedScanList.add(new BatchedScanResult(result));
873             }
874             return batchedScanList;
875         }
876     }
877 
requestBatchedScanPoll()878     public void requestBatchedScanPoll() {
879         sendMessage(CMD_POLL_BATCHED_SCAN);
880     }
881 
startBatchedScan()882     private void startBatchedScan() {
883         if (mBatchedScanSettings == null) return;
884 
885         if (mDhcpActive) {
886             if (DBG) log("not starting Batched Scans due to DHCP");
887             return;
888         }
889 
890         // first grab any existing data
891         retrieveBatchedScanData();
892 
893         mAlarmManager.cancel(mBatchedScanIntervalIntent);
894 
895         String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
896         try {
897             mExpectedBatchedScans = Integer.parseInt(scansExpected);
898             setNextBatchedAlarm(mExpectedBatchedScans);
899             if (mExpectedBatchedScans > 0) noteBatchedScanStart();
900         } catch (NumberFormatException e) {
901             stopBatchedScan();
902             loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
903         }
904     }
905 
906     // called from BroadcastListener
startNextBatchedScanAsync()907     private void startNextBatchedScanAsync() {
908         sendMessage(CMD_START_NEXT_BATCHED_SCAN);
909     }
910 
startNextBatchedScan()911     private void startNextBatchedScan() {
912         // first grab any existing data
913         retrieveBatchedScanData();
914 
915         setNextBatchedAlarm(mExpectedBatchedScans);
916     }
917 
handleBatchedScanPollRequest()918     private void handleBatchedScanPollRequest() {
919         if (DBG) {
920             log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" +
921                     mBatchedScanMinPollTime + " , mBatchedScanSettings=" +
922                     mBatchedScanSettings);
923         }
924         // if there is no appropriate PollTime that's because we either aren't
925         // batching or we've already set a time for a poll request
926         if (mBatchedScanMinPollTime == 0) return;
927         if (mBatchedScanSettings == null) return;
928 
929         long now = System.currentTimeMillis();
930 
931         if (now > mBatchedScanMinPollTime) {
932             // do the poll and reset our timers
933             startNextBatchedScan();
934         } else {
935             mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
936                     mBatchedScanIntervalIntent);
937             mBatchedScanMinPollTime = 0;
938         }
939     }
940 
941     // return true if new/different
recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle)942     private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) {
943         BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING);
944         WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE);
945 
946         if (DBG) {
947             log("set batched scan to " + settings + " for uid=" + responsibleUid +
948                     ", worksource=" + responsibleWorkSource);
949         }
950         if (settings != null) {
951             if (settings.equals(mBatchedScanSettings)) return false;
952         } else {
953             if (mBatchedScanSettings == null) return false;
954         }
955         mBatchedScanSettings = settings;
956         if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid);
957         mBatchedScanWorkSource = responsibleWorkSource;
958         mBatchedScanCsph = csph;
959         return true;
960     }
961 
stopBatchedScan()962     private void stopBatchedScan() {
963         mAlarmManager.cancel(mBatchedScanIntervalIntent);
964         retrieveBatchedScanData();
965         mWifiNative.setBatchedScanSettings(null);
966         noteBatchedScanStop();
967     }
968 
setNextBatchedAlarm(int scansExpected)969     private void setNextBatchedAlarm(int scansExpected) {
970 
971         if (mBatchedScanSettings == null || scansExpected < 1) return;
972 
973         mBatchedScanMinPollTime = System.currentTimeMillis() +
974                 mBatchedScanSettings.scanIntervalSec * 1000;
975 
976         if (mBatchedScanSettings.maxScansPerBatch < scansExpected) {
977             scansExpected = mBatchedScanSettings.maxScansPerBatch;
978         }
979 
980         int secToFull = mBatchedScanSettings.scanIntervalSec;
981         secToFull *= scansExpected;
982 
983         int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0);
984         if (debugPeriod > 0) secToFull = debugPeriod;
985 
986         // set the alarm to do the next poll.  We set it a little short as we'd rather
987         // wake up wearly than miss a scan due to buffer overflow
988         mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
989                 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000),
990                 mBatchedScanIntervalIntent);
991     }
992 
993     /**
994      * Start reading new scan data
995      * Data comes in as:
996      * "scancount=5\n"
997      * "nextcount=5\n"
998      *   "apcount=3\n"
999      *   "trunc\n" (optional)
1000      *     "bssid=...\n"
1001      *     "ssid=...\n"
1002      *     "freq=...\n" (in Mhz)
1003      *     "level=...\n"
1004      *     "dist=...\n" (in cm)
1005      *     "distsd=...\n" (standard deviation, in cm)
1006      *     "===="
1007      *     "bssid=...\n"
1008      *     etc
1009      *     "===="
1010      *     "bssid=...\n"
1011      *     etc
1012      *     "%%%%"
1013      *   "apcount=2\n"
1014      *     "bssid=...\n"
1015      *     etc
1016      *     "%%%%
1017      *   etc
1018      *   "----"
1019      */
1020     private final static boolean DEBUG_PARSE = false;
retrieveBatchedScanData()1021     private void retrieveBatchedScanData() {
1022         String rawData = mWifiNative.getBatchedScanResults();
1023         if (DEBUG_PARSE) log("rawData = " + rawData);
1024         mBatchedScanMinPollTime = 0;
1025         if (rawData == null || rawData.equalsIgnoreCase("OK")) {
1026             loge("Unexpected BatchedScanResults :" + rawData);
1027             return;
1028         }
1029 
1030         int scanCount = 0;
1031         final String END_OF_BATCHES = "----";
1032         final String SCANCOUNT = "scancount=";
1033         final String TRUNCATED = "trunc";
1034         final String AGE = "age=";
1035         final String DIST = "dist=";
1036         final String DISTSD = "distSd=";
1037 
1038         String splitData[] = rawData.split("\n");
1039         int n = 0;
1040         if (splitData[n].startsWith(SCANCOUNT)) {
1041             try {
1042                 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length()));
1043             } catch (NumberFormatException e) {
1044                 loge("scancount parseInt Exception from " + splitData[n]);
1045             }
1046         } else log("scancount not found");
1047         if (scanCount == 0) {
1048             loge("scanCount==0 - aborting");
1049             return;
1050         }
1051 
1052         final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION);
1053         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1054 
1055         synchronized (mBatchedScanResults) {
1056             mBatchedScanResults.clear();
1057             BatchedScanResult batchedScanResult = new BatchedScanResult();
1058 
1059             String bssid = null;
1060             WifiSsid wifiSsid = null;
1061             int level = 0;
1062             int freq = 0;
1063             int dist, distSd;
1064             long tsf = 0;
1065             dist = distSd = ScanResult.UNSPECIFIED;
1066             final long now = SystemClock.elapsedRealtime();
1067             final int bssidStrLen = BSSID_STR.length();
1068 
1069             while (true) {
1070                 while (n < splitData.length) {
1071                     if (DEBUG_PARSE) logd("parsing " + splitData[n]);
1072                     if (splitData[n].equals(END_OF_BATCHES)) {
1073                         if (n+1 != splitData.length) {
1074                             loge("didn't consume " + (splitData.length-n));
1075                         }
1076                         if (mBatchedScanResults.size() > 0) {
1077                             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1078                         }
1079                         logd("retrieveBatchedScanResults X");
1080                         return;
1081                     }
1082                     if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) {
1083                         if (bssid != null) {
1084                             batchedScanResult.scanResults.add(new ScanResult(
1085                                     wifiSsid, bssid, "", level, freq, tsf, dist, distSd));
1086                             wifiSsid = null;
1087                             bssid = null;
1088                             level = 0;
1089                             freq = 0;
1090                             tsf = 0;
1091                             dist = distSd = ScanResult.UNSPECIFIED;
1092                         }
1093                         if (splitData[n].equals(END_STR)) {
1094                             if (batchedScanResult.scanResults.size() != 0) {
1095                                 mBatchedScanResults.add(batchedScanResult);
1096                                 batchedScanResult = new BatchedScanResult();
1097                             } else {
1098                                 logd("Found empty batch");
1099                             }
1100                         }
1101                     } else if (splitData[n].equals(TRUNCATED)) {
1102                         batchedScanResult.truncated = true;
1103                     } else if (splitData[n].startsWith(BSSID_STR)) {
1104                         bssid = new String(splitData[n].getBytes(), bssidStrLen,
1105                                 splitData[n].length() - bssidStrLen);
1106                     } else if (splitData[n].startsWith(FREQ_STR)) {
1107                         try {
1108                             freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length()));
1109                         } catch (NumberFormatException e) {
1110                             loge("Invalid freqency: " + splitData[n]);
1111                             freq = 0;
1112                         }
1113                     } else if (splitData[n].startsWith(AGE)) {
1114                         try {
1115                             tsf = now - Long.parseLong(splitData[n].substring(AGE.length()));
1116                             tsf *= 1000; // convert mS -> uS
1117                         } catch (NumberFormatException e) {
1118                             loge("Invalid timestamp: " + splitData[n]);
1119                             tsf = 0;
1120                         }
1121                     } else if (splitData[n].startsWith(SSID_STR)) {
1122                         wifiSsid = WifiSsid.createFromAsciiEncoded(
1123                                 splitData[n].substring(SSID_STR.length()));
1124                     } else if (splitData[n].startsWith(LEVEL_STR)) {
1125                         try {
1126                             level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length()));
1127                             if (level > 0) level -= 256;
1128                         } catch (NumberFormatException e) {
1129                             loge("Invalid level: " + splitData[n]);
1130                             level = 0;
1131                         }
1132                     } else if (splitData[n].startsWith(DIST)) {
1133                         try {
1134                             dist = Integer.parseInt(splitData[n].substring(DIST.length()));
1135                         } catch (NumberFormatException e) {
1136                             loge("Invalid distance: " + splitData[n]);
1137                             dist = ScanResult.UNSPECIFIED;
1138                         }
1139                     } else if (splitData[n].startsWith(DISTSD)) {
1140                         try {
1141                             distSd = Integer.parseInt(splitData[n].substring(DISTSD.length()));
1142                         } catch (NumberFormatException e) {
1143                             loge("Invalid distanceSd: " + splitData[n]);
1144                             distSd = ScanResult.UNSPECIFIED;
1145                         }
1146                     } else {
1147                         loge("Unable to parse batched scan result line: " + splitData[n]);
1148                     }
1149                     n++;
1150                 }
1151                 rawData = mWifiNative.getBatchedScanResults();
1152                 if (DEBUG_PARSE) log("reading more data:\n" + rawData);
1153                 if (rawData == null) {
1154                     loge("Unexpected null BatchedScanResults");
1155                     return;
1156                 }
1157                 splitData = rawData.split("\n");
1158                 if (splitData.length == 0 || splitData[0].equals("ok")) {
1159                     loge("batch scan results just ended!");
1160                     if (mBatchedScanResults.size() > 0) {
1161                         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1162                     }
1163                     return;
1164                 }
1165                 n = 0;
1166             }
1167         }
1168     }
1169 
1170     // If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
noteScanStart(int callingUid, WorkSource workSource)1171     private void noteScanStart(int callingUid, WorkSource workSource) {
1172         if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) {
1173             mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid);
1174             try {
1175                 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource);
1176             } catch (RemoteException e) {
1177                 log(e.toString());
1178             }
1179         }
1180     }
1181 
noteScanEnd()1182     private void noteScanEnd() {
1183         if (mScanWorkSource != null) {
1184             try {
1185                 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
1186             } catch (RemoteException e) {
1187                 log(e.toString());
1188             } finally {
1189                 mScanWorkSource = null;
1190             }
1191         }
1192     }
1193 
noteBatchedScanStart()1194     private void noteBatchedScanStart() {
1195         // note the end of a previous scan set
1196         if (mNotedBatchedScanWorkSource != null &&
1197                 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false ||
1198                  mNotedBatchedScanCsph != mBatchedScanCsph)) {
1199             try {
1200                 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
1201             } catch (RemoteException e) {
1202                 log(e.toString());
1203             } finally {
1204                 mNotedBatchedScanWorkSource = null;
1205                 mNotedBatchedScanCsph = 0;
1206             }
1207         }
1208         // note the start of the new
1209         try {
1210             mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource,
1211                     mBatchedScanCsph);
1212             mNotedBatchedScanWorkSource = mBatchedScanWorkSource;
1213             mNotedBatchedScanCsph = mBatchedScanCsph;
1214         } catch (RemoteException e) {
1215             log(e.toString());
1216         }
1217     }
1218 
noteBatchedScanStop()1219     private void noteBatchedScanStop() {
1220         if (mNotedBatchedScanWorkSource != null) {
1221             try {
1222                 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
1223             } catch (RemoteException e) {
1224                 log(e.toString());
1225             } finally {
1226                 mNotedBatchedScanWorkSource = null;
1227                 mNotedBatchedScanCsph = 0;
1228             }
1229         }
1230     }
1231 
startScanNative(int type)1232     private void startScanNative(int type) {
1233         mWifiNative.scan(type);
1234         mScanResultIsPending = true;
1235     }
1236 
1237     /**
1238      * TODO: doc
1239      */
setSupplicantRunning(boolean enable)1240     public void setSupplicantRunning(boolean enable) {
1241         if (enable) {
1242             sendMessage(CMD_START_SUPPLICANT);
1243         } else {
1244             sendMessage(CMD_STOP_SUPPLICANT);
1245         }
1246     }
1247 
1248     /**
1249      * TODO: doc
1250      */
setHostApRunning(WifiConfiguration wifiConfig, boolean enable)1251     public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
1252         if (enable) {
1253             sendMessage(CMD_START_AP, wifiConfig);
1254         } else {
1255             sendMessage(CMD_STOP_AP);
1256         }
1257     }
1258 
setWifiApConfiguration(WifiConfiguration config)1259     public void setWifiApConfiguration(WifiConfiguration config) {
1260         mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
1261     }
1262 
syncGetWifiApConfiguration()1263     public WifiConfiguration syncGetWifiApConfiguration() {
1264         Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
1265         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
1266         resultMsg.recycle();
1267         return ret;
1268     }
1269 
1270     /**
1271      * TODO: doc
1272      */
syncGetWifiState()1273     public int syncGetWifiState() {
1274         return mWifiState.get();
1275     }
1276 
1277     /**
1278      * TODO: doc
1279      */
syncGetWifiStateByName()1280     public String syncGetWifiStateByName() {
1281         switch (mWifiState.get()) {
1282             case WIFI_STATE_DISABLING:
1283                 return "disabling";
1284             case WIFI_STATE_DISABLED:
1285                 return "disabled";
1286             case WIFI_STATE_ENABLING:
1287                 return "enabling";
1288             case WIFI_STATE_ENABLED:
1289                 return "enabled";
1290             case WIFI_STATE_UNKNOWN:
1291                 return "unknown state";
1292             default:
1293                 return "[invalid state]";
1294         }
1295     }
1296 
1297     /**
1298      * TODO: doc
1299      */
syncGetWifiApState()1300     public int syncGetWifiApState() {
1301         return mWifiApState.get();
1302     }
1303 
1304     /**
1305      * TODO: doc
1306      */
syncGetWifiApStateByName()1307     public String syncGetWifiApStateByName() {
1308         switch (mWifiApState.get()) {
1309             case WIFI_AP_STATE_DISABLING:
1310                 return "disabling";
1311             case WIFI_AP_STATE_DISABLED:
1312                 return "disabled";
1313             case WIFI_AP_STATE_ENABLING:
1314                 return "enabling";
1315             case WIFI_AP_STATE_ENABLED:
1316                 return "enabled";
1317             case WIFI_AP_STATE_FAILED:
1318                 return "failed";
1319             default:
1320                 return "[invalid state]";
1321         }
1322     }
1323 
1324     /**
1325      * Get status information for the current connection, if any.
1326      * @return a {@link WifiInfo} object containing information about the current connection
1327      *
1328      */
syncRequestConnectionInfo()1329     public WifiInfo syncRequestConnectionInfo() {
1330         return mWifiInfo;
1331     }
1332 
syncGetDhcpResults()1333     public DhcpResults syncGetDhcpResults() {
1334         synchronized (mDhcpResultsLock) {
1335             return new DhcpResults(mDhcpResults);
1336         }
1337     }
1338 
1339     /**
1340      * TODO: doc
1341      */
setDriverStart(boolean enable)1342     public void setDriverStart(boolean enable) {
1343         if (enable) {
1344             sendMessage(CMD_START_DRIVER);
1345         } else {
1346             sendMessage(CMD_STOP_DRIVER);
1347         }
1348     }
1349 
captivePortalCheckComplete()1350     public void captivePortalCheckComplete() {
1351         sendMessage(CMD_CAPTIVE_CHECK_COMPLETE);
1352     }
1353 
1354     /**
1355      * TODO: doc
1356      */
setOperationalMode(int mode)1357     public void setOperationalMode(int mode) {
1358         if (DBG) log("setting operational mode to " + String.valueOf(mode));
1359         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
1360     }
1361 
1362     /**
1363      * TODO: doc
1364      */
syncGetScanResultsList()1365     public List<ScanResult> syncGetScanResultsList() {
1366         synchronized (mScanResultCache) {
1367             List<ScanResult> scanList = new ArrayList<ScanResult>();
1368             for(ScanResult result: mScanResults) {
1369                 scanList.add(new ScanResult(result));
1370             }
1371             return scanList;
1372         }
1373     }
1374 
1375     /**
1376      * Disconnect from Access Point
1377      */
disconnectCommand()1378     public void disconnectCommand() {
1379         sendMessage(CMD_DISCONNECT);
1380     }
1381 
1382     /**
1383      * Initiate a reconnection to AP
1384      */
reconnectCommand()1385     public void reconnectCommand() {
1386         sendMessage(CMD_RECONNECT);
1387     }
1388 
1389     /**
1390      * Initiate a re-association to AP
1391      */
reassociateCommand()1392     public void reassociateCommand() {
1393         sendMessage(CMD_REASSOCIATE);
1394     }
1395 
1396     /**
1397      * Reload networks and then reconnect; helps load correct data for TLS networks
1398      */
1399 
reloadTlsNetworksAndReconnect()1400     public void reloadTlsNetworksAndReconnect() {
1401         sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
1402     }
1403 
1404     /**
1405      * Add a network synchronously
1406      *
1407      * @return network id of the new network
1408      */
syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config)1409     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
1410         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
1411         int result = resultMsg.arg1;
1412         resultMsg.recycle();
1413         return result;
1414     }
1415 
syncGetConfiguredNetworks(AsyncChannel channel)1416     public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) {
1417         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS);
1418         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
1419         resultMsg.recycle();
1420         return result;
1421     }
1422 
1423     /**
1424      * Delete a network
1425      *
1426      * @param networkId id of the network to be removed
1427      */
syncRemoveNetwork(AsyncChannel channel, int networkId)1428     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
1429         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
1430         boolean result = (resultMsg.arg1 != FAILURE);
1431         resultMsg.recycle();
1432         return result;
1433     }
1434 
1435     /**
1436      * Enable a network
1437      *
1438      * @param netId network id of the network
1439      * @param disableOthers true, if all other networks have to be disabled
1440      * @return {@code true} if the operation succeeds, {@code false} otherwise
1441      */
syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers)1442     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
1443         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
1444                 disableOthers ? 1 : 0);
1445         boolean result = (resultMsg.arg1 != FAILURE);
1446         resultMsg.recycle();
1447         return result;
1448     }
1449 
1450     /**
1451      * Disable a network
1452      *
1453      * @param netId network id of the network
1454      * @return {@code true} if the operation succeeds, {@code false} otherwise
1455      */
syncDisableNetwork(AsyncChannel channel, int netId)1456     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
1457         Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
1458         boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
1459         resultMsg.recycle();
1460         return result;
1461     }
1462 
1463     /**
1464      * Blacklist a BSSID. This will avoid the AP if there are
1465      * alternate APs to connect
1466      *
1467      * @param bssid BSSID of the network
1468      */
addToBlacklist(String bssid)1469     public void addToBlacklist(String bssid) {
1470         sendMessage(CMD_BLACKLIST_NETWORK, bssid);
1471     }
1472 
1473     /**
1474      * Clear the blacklist list
1475      *
1476      */
clearBlacklist()1477     public void clearBlacklist() {
1478         sendMessage(CMD_CLEAR_BLACKLIST);
1479     }
1480 
enableRssiPolling(boolean enabled)1481     public void enableRssiPolling(boolean enabled) {
1482        sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
1483     }
1484 
enableBackgroundScanCommand(boolean enabled)1485     public void enableBackgroundScanCommand(boolean enabled) {
1486        sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0);
1487     }
1488 
enableAllNetworks()1489     public void enableAllNetworks() {
1490         sendMessage(CMD_ENABLE_ALL_NETWORKS);
1491     }
1492 
1493     /**
1494      * Start filtering Multicast v4 packets
1495      */
startFilteringMulticastV4Packets()1496     public void startFilteringMulticastV4Packets() {
1497         mFilteringMulticastV4Packets.set(true);
1498         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
1499     }
1500 
1501     /**
1502      * Stop filtering Multicast v4 packets
1503      */
stopFilteringMulticastV4Packets()1504     public void stopFilteringMulticastV4Packets() {
1505         mFilteringMulticastV4Packets.set(false);
1506         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
1507     }
1508 
1509     /**
1510      * Start filtering Multicast v4 packets
1511      */
startFilteringMulticastV6Packets()1512     public void startFilteringMulticastV6Packets() {
1513         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
1514     }
1515 
1516     /**
1517      * Stop filtering Multicast v4 packets
1518      */
stopFilteringMulticastV6Packets()1519     public void stopFilteringMulticastV6Packets() {
1520         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
1521     }
1522 
1523     /**
1524      * Set high performance mode of operation.
1525      * Enabling would set active power mode and disable suspend optimizations;
1526      * disabling would set auto power mode and enable suspend optimizations
1527      * @param enable true if enable, false otherwise
1528      */
setHighPerfModeEnabled(boolean enable)1529     public void setHighPerfModeEnabled(boolean enable) {
1530         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
1531     }
1532 
1533     /**
1534      * Set the country code
1535      * @param countryCode following ISO 3166 format
1536      * @param persist {@code true} if the setting should be remembered.
1537      */
setCountryCode(String countryCode, boolean persist)1538     public void setCountryCode(String countryCode, boolean persist) {
1539         // If it's a good country code, apply after the current
1540         // wifi connection is terminated; ignore resetting of code
1541         // for now (it is unclear what the chipset should do when
1542         // country code is reset)
1543         int countryCodeSequence = mCountryCodeSequence.incrementAndGet();
1544         if (TextUtils.isEmpty(countryCode)) {
1545             log("Ignoring resetting of country code");
1546         } else {
1547             sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode);
1548         }
1549     }
1550 
1551     /**
1552      * Set the operational frequency band
1553      * @param band
1554      * @param persist {@code true} if the setting should be remembered.
1555      */
setFrequencyBand(int band, boolean persist)1556     public void setFrequencyBand(int band, boolean persist) {
1557         if (persist) {
1558             Settings.Global.putInt(mContext.getContentResolver(),
1559                     Settings.Global.WIFI_FREQUENCY_BAND,
1560                     band);
1561         }
1562         sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
1563     }
1564 
1565     /**
1566      * Enable TDLS for a specific MAC address
1567      */
enableTdls(String remoteMacAddress, boolean enable)1568     public void enableTdls(String remoteMacAddress, boolean enable) {
1569         int enabler = enable ? 1 : 0;
1570         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
1571     }
1572 
1573     /**
1574      * Returns the operational frequency band
1575      */
getFrequencyBand()1576     public int getFrequencyBand() {
1577         return mFrequencyBand.get();
1578     }
1579 
1580     /**
1581      * Returns the wifi configuration file
1582      */
getConfigFile()1583     public String getConfigFile() {
1584         return mWifiConfigStore.getConfigFile();
1585     }
1586 
1587     /**
1588      * Send a message indicating bluetooth adapter connection state changed
1589      */
sendBluetoothAdapterStateChange(int state)1590     public void sendBluetoothAdapterStateChange(int state) {
1591         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
1592     }
1593 
1594     /**
1595      * Save configuration on supplicant
1596      *
1597      * @return {@code true} if the operation succeeds, {@code false} otherwise
1598      *
1599      * TODO: deprecate this
1600      */
syncSaveConfig(AsyncChannel channel)1601     public boolean syncSaveConfig(AsyncChannel channel) {
1602         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
1603         boolean result = (resultMsg.arg1 != FAILURE);
1604         resultMsg.recycle();
1605         return result;
1606     }
1607 
updateBatteryWorkSource(WorkSource newSource)1608     public void updateBatteryWorkSource(WorkSource newSource) {
1609         synchronized (mRunningWifiUids) {
1610             try {
1611                 if (newSource != null) {
1612                     mRunningWifiUids.set(newSource);
1613                 }
1614                 if (mIsRunning) {
1615                     if (mReportedRunning) {
1616                         // If the work source has changed since last time, need
1617                         // to remove old work from battery stats.
1618                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
1619                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
1620                                     mRunningWifiUids);
1621                             mLastRunningWifiUids.set(mRunningWifiUids);
1622                         }
1623                     } else {
1624                         // Now being started, report it.
1625                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
1626                         mLastRunningWifiUids.set(mRunningWifiUids);
1627                         mReportedRunning = true;
1628                     }
1629                 } else {
1630                     if (mReportedRunning) {
1631                         // Last reported we were running, time to stop.
1632                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
1633                         mLastRunningWifiUids.clear();
1634                         mReportedRunning = false;
1635                     }
1636                 }
1637                 mWakeLock.setWorkSource(newSource);
1638             } catch (RemoteException ignore) {
1639             }
1640         }
1641     }
1642 
1643     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1644     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1645         super.dump(fd, pw, args);
1646         mSupplicantStateTracker.dump(fd, pw, args);
1647         pw.println("mLinkProperties " + mLinkProperties);
1648         pw.println("mWifiInfo " + mWifiInfo);
1649         pw.println("mDhcpResults " + mDhcpResults);
1650         pw.println("mNetworkInfo " + mNetworkInfo);
1651         pw.println("mLastSignalLevel " + mLastSignalLevel);
1652         pw.println("mLastBssid " + mLastBssid);
1653         pw.println("mLastNetworkId " + mLastNetworkId);
1654         pw.println("mReconnectCount " + mReconnectCount);
1655         pw.println("mOperationalMode " + mOperationalMode);
1656         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
1657         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
1658         pw.println("Supplicant status " + mWifiNative.status());
1659         pw.println("mEnableBackgroundScan " + mEnableBackgroundScan);
1660         pw.println("mLastSetCountryCode " + mLastSetCountryCode);
1661         pw.println("mPersistedCountryCode " + mPersistedCountryCode);
1662         pw.println();
1663         mWifiConfigStore.dump(fd, pw, args);
1664     }
1665 
1666     /*********************************************************
1667      * Internal private functions
1668      ********************************************************/
1669 
handleScreenStateChanged(boolean screenOn)1670     private void handleScreenStateChanged(boolean screenOn) {
1671         if (DBG) log("handleScreenStateChanged: " + screenOn);
1672         enableRssiPolling(screenOn);
1673         if (mBackgroundScanSupported) {
1674             enableBackgroundScanCommand(screenOn == false);
1675         }
1676 
1677         if (screenOn) enableAllNetworks();
1678         if (mUserWantsSuspendOpt.get()) {
1679             if (screenOn) {
1680                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
1681             } else {
1682                 //Allow 2s for suspend optimizations to be set
1683                 mSuspendWakeLock.acquire(2000);
1684                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
1685             }
1686         }
1687         mScreenBroadcastReceived.set(true);
1688     }
1689 
checkAndSetConnectivityInstance()1690     private void checkAndSetConnectivityInstance() {
1691         if (mCm == null) {
1692             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1693         }
1694     }
1695 
startTethering(ArrayList<String> available)1696     private boolean startTethering(ArrayList<String> available) {
1697 
1698         boolean wifiAvailable = false;
1699 
1700         checkAndSetConnectivityInstance();
1701 
1702         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1703 
1704         for (String intf : available) {
1705             for (String regex : wifiRegexs) {
1706                 if (intf.matches(regex)) {
1707 
1708                     InterfaceConfiguration ifcg = null;
1709                     try {
1710                         ifcg = mNwService.getInterfaceConfig(intf);
1711                         if (ifcg != null) {
1712                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
1713                             ifcg.setLinkAddress(new LinkAddress(
1714                                     NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
1715                             ifcg.setInterfaceUp();
1716 
1717                             mNwService.setInterfaceConfig(intf, ifcg);
1718                         }
1719                     } catch (Exception e) {
1720                         loge("Error configuring interface " + intf + ", :" + e);
1721                         return false;
1722                     }
1723 
1724                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1725                         loge("Error tethering on " + intf);
1726                         return false;
1727                     }
1728                     mTetherInterfaceName = intf;
1729                     return true;
1730                 }
1731             }
1732         }
1733         // We found no interfaces to tether
1734         return false;
1735     }
1736 
stopTethering()1737     private void stopTethering() {
1738 
1739         checkAndSetConnectivityInstance();
1740 
1741         /* Clear the interface config to allow dhcp correctly configure new
1742            ip settings */
1743         InterfaceConfiguration ifcg = null;
1744         try {
1745             ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
1746             if (ifcg != null) {
1747                 ifcg.setLinkAddress(
1748                         new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
1749                 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
1750             }
1751         } catch (Exception e) {
1752             loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
1753         }
1754 
1755         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1756             loge("Untether initiate failed!");
1757         }
1758     }
1759 
isWifiTethered(ArrayList<String> active)1760     private boolean isWifiTethered(ArrayList<String> active) {
1761 
1762         checkAndSetConnectivityInstance();
1763 
1764         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1765         for (String intf : active) {
1766             for (String regex : wifiRegexs) {
1767                 if (intf.matches(regex)) {
1768                     return true;
1769                 }
1770             }
1771         }
1772         // We found no interfaces that are tethered
1773         return false;
1774     }
1775 
1776     /**
1777      * Set the country code from the system setting value, if any.
1778      */
setCountryCode()1779     private void setCountryCode() {
1780         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
1781                 Settings.Global.WIFI_COUNTRY_CODE);
1782         if (countryCode != null && !countryCode.isEmpty()) {
1783             setCountryCode(countryCode, false);
1784         } else {
1785             //use driver default
1786         }
1787     }
1788 
1789     /**
1790      * Set the frequency band from the system setting value, if any.
1791      */
setFrequencyBand()1792     private void setFrequencyBand() {
1793         int band = Settings.Global.getInt(mContext.getContentResolver(),
1794                 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1795         setFrequencyBand(band, false);
1796     }
1797 
setSuspendOptimizationsNative(int reason, boolean enabled)1798     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
1799         if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled);
1800         if (enabled) {
1801             mSuspendOptNeedsDisabled &= ~reason;
1802             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
1803             if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
1804                 mWifiNative.setSuspendOptimizations(true);
1805             }
1806         } else {
1807             mSuspendOptNeedsDisabled |= reason;
1808             mWifiNative.setSuspendOptimizations(false);
1809         }
1810     }
1811 
setSuspendOptimizations(int reason, boolean enabled)1812     private void setSuspendOptimizations(int reason, boolean enabled) {
1813         if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
1814         if (enabled) {
1815             mSuspendOptNeedsDisabled &= ~reason;
1816         } else {
1817             mSuspendOptNeedsDisabled |= reason;
1818         }
1819         if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
1820     }
1821 
setWifiState(int wifiState)1822     private void setWifiState(int wifiState) {
1823         final int previousWifiState = mWifiState.get();
1824 
1825         try {
1826             if (wifiState == WIFI_STATE_ENABLED) {
1827                 mBatteryStats.noteWifiOn();
1828             } else if (wifiState == WIFI_STATE_DISABLED) {
1829                 mBatteryStats.noteWifiOff();
1830             }
1831         } catch (RemoteException e) {
1832             loge("Failed to note battery stats in wifi");
1833         }
1834 
1835         mWifiState.set(wifiState);
1836 
1837         if (DBG) log("setWifiState: " + syncGetWifiStateByName());
1838 
1839         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1840         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1841         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1842         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1843         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1844     }
1845 
setWifiApState(int wifiApState)1846     private void setWifiApState(int wifiApState) {
1847         final int previousWifiApState = mWifiApState.get();
1848 
1849         try {
1850             if (wifiApState == WIFI_AP_STATE_ENABLED) {
1851                 mBatteryStats.noteWifiOn();
1852             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1853                 mBatteryStats.noteWifiOff();
1854             }
1855         } catch (RemoteException e) {
1856             loge("Failed to note battery stats in wifi");
1857         }
1858 
1859         // Update state
1860         mWifiApState.set(wifiApState);
1861 
1862         if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
1863 
1864         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1865         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1866         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1867         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1868         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1869     }
1870 
1871     private static final String ID_STR = "id=";
1872     private static final String BSSID_STR = "bssid=";
1873     private static final String FREQ_STR = "freq=";
1874     private static final String LEVEL_STR = "level=";
1875     private static final String TSF_STR = "tsf=";
1876     private static final String FLAGS_STR = "flags=";
1877     private static final String SSID_STR = "ssid=";
1878     private static final String DELIMITER_STR = "====";
1879     private static final String END_STR = "####";
1880 
1881     /**
1882      * Format:
1883      *
1884      * id=1
1885      * bssid=68:7f:76:d7:1a:6e
1886      * freq=2412
1887      * level=-44
1888      * tsf=1344626243700342
1889      * flags=[WPA2-PSK-CCMP][WPS][ESS]
1890      * ssid=zfdy
1891      * ====
1892      * id=2
1893      * bssid=68:5f:74:d7:1a:6f
1894      * freq=5180
1895      * level=-73
1896      * tsf=1344626243700373
1897      * flags=[WPA2-PSK-CCMP][WPS][ESS]
1898      * ssid=zuby
1899      * ====
1900      */
setScanResults()1901     private void setScanResults() {
1902         String bssid = "";
1903         int level = 0;
1904         int freq = 0;
1905         long tsf = 0;
1906         String flags = "";
1907         WifiSsid wifiSsid = null;
1908         String scanResults;
1909         String tmpResults;
1910         StringBuffer scanResultsBuf = new StringBuffer();
1911         int sid = 0;
1912 
1913         while (true) {
1914             tmpResults = mWifiNative.scanResults(sid);
1915             if (TextUtils.isEmpty(tmpResults)) break;
1916             scanResultsBuf.append(tmpResults);
1917             scanResultsBuf.append("\n");
1918             String[] lines = tmpResults.split("\n");
1919             sid = -1;
1920             for (int i=lines.length - 1; i >= 0; i--) {
1921                 if (lines[i].startsWith(END_STR)) {
1922                     break;
1923                 } else if (lines[i].startsWith(ID_STR)) {
1924                     try {
1925                         sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
1926                     } catch (NumberFormatException e) {
1927                         // Nothing to do
1928                     }
1929                     break;
1930                 }
1931             }
1932             if (sid == -1) break;
1933         }
1934 
1935         scanResults = scanResultsBuf.toString();
1936         if (TextUtils.isEmpty(scanResults)) {
1937            return;
1938         }
1939 
1940         // note that all these splits and substrings keep references to the original
1941         // huge string buffer while the amount we really want is generally pretty small
1942         // so make copies instead (one example b/11087956 wasted 400k of heap here).
1943         synchronized(mScanResultCache) {
1944             mScanResults = new ArrayList<ScanResult>();
1945             String[] lines = scanResults.split("\n");
1946             final int bssidStrLen = BSSID_STR.length();
1947             final int flagLen = FLAGS_STR.length();
1948 
1949             for (String line : lines) {
1950                 if (line.startsWith(BSSID_STR)) {
1951                     bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
1952                 } else if (line.startsWith(FREQ_STR)) {
1953                     try {
1954                         freq = Integer.parseInt(line.substring(FREQ_STR.length()));
1955                     } catch (NumberFormatException e) {
1956                         freq = 0;
1957                     }
1958                 } else if (line.startsWith(LEVEL_STR)) {
1959                     try {
1960                         level = Integer.parseInt(line.substring(LEVEL_STR.length()));
1961                         /* some implementations avoid negative values by adding 256
1962                          * so we need to adjust for that here.
1963                          */
1964                         if (level > 0) level -= 256;
1965                     } catch(NumberFormatException e) {
1966                         level = 0;
1967                     }
1968                 } else if (line.startsWith(TSF_STR)) {
1969                     try {
1970                         tsf = Long.parseLong(line.substring(TSF_STR.length()));
1971                     } catch (NumberFormatException e) {
1972                         tsf = 0;
1973                     }
1974                 } else if (line.startsWith(FLAGS_STR)) {
1975                     flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
1976                 } else if (line.startsWith(SSID_STR)) {
1977                     wifiSsid = WifiSsid.createFromAsciiEncoded(
1978                             line.substring(SSID_STR.length()));
1979                 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
1980                     if (bssid != null) {
1981                         String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
1982                         String key = bssid + ssid;
1983                         ScanResult scanResult = mScanResultCache.get(key);
1984                         if (scanResult != null) {
1985                             scanResult.level = level;
1986                             scanResult.wifiSsid = wifiSsid;
1987                             // Keep existing API
1988                             scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() :
1989                                     WifiSsid.NONE;
1990                             scanResult.capabilities = flags;
1991                             scanResult.frequency = freq;
1992                             scanResult.timestamp = tsf;
1993                         } else {
1994                             scanResult =
1995                                 new ScanResult(
1996                                         wifiSsid, bssid, flags, level, freq, tsf);
1997                             mScanResultCache.put(key, scanResult);
1998                         }
1999                         mScanResults.add(scanResult);
2000                     }
2001                     bssid = null;
2002                     level = 0;
2003                     freq = 0;
2004                     tsf = 0;
2005                     flags = "";
2006                     wifiSsid = null;
2007                 }
2008             }
2009         }
2010     }
2011 
2012     /*
2013      * Fetch RSSI and linkspeed on current connection
2014      */
fetchRssiAndLinkSpeedNative()2015     private void fetchRssiAndLinkSpeedNative() {
2016         int newRssi = -1;
2017         int newLinkSpeed = -1;
2018 
2019         String signalPoll = mWifiNative.signalPoll();
2020 
2021         if (signalPoll != null) {
2022             String[] lines = signalPoll.split("\n");
2023             for (String line : lines) {
2024                 String[] prop = line.split("=");
2025                 if (prop.length < 2) continue;
2026                 try {
2027                     if (prop[0].equals("RSSI")) {
2028                         newRssi = Integer.parseInt(prop[1]);
2029                     } else if (prop[0].equals("LINKSPEED")) {
2030                         newLinkSpeed = Integer.parseInt(prop[1]);
2031                     }
2032                 } catch (NumberFormatException e) {
2033                     //Ignore, defaults on rssi and linkspeed are assigned
2034                 }
2035             }
2036         }
2037 
2038         if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
2039             /* some implementations avoid negative values by adding 256
2040              * so we need to adjust for that here.
2041              */
2042             if (newRssi > 0) newRssi -= 256;
2043             mWifiInfo.setRssi(newRssi);
2044             /*
2045              * Rather then sending the raw RSSI out every time it
2046              * changes, we precalculate the signal level that would
2047              * be displayed in the status bar, and only send the
2048              * broadcast if that much more coarse-grained number
2049              * changes. This cuts down greatly on the number of
2050              * broadcasts, at the cost of not informing others
2051              * interested in RSSI of all the changes in signal
2052              * level.
2053              */
2054             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
2055             if (newSignalLevel != mLastSignalLevel) {
2056                 sendRssiChangeBroadcast(newRssi);
2057             }
2058             mLastSignalLevel = newSignalLevel;
2059         } else {
2060             mWifiInfo.setRssi(MIN_RSSI);
2061         }
2062 
2063         if (newLinkSpeed != -1) {
2064             mWifiInfo.setLinkSpeed(newLinkSpeed);
2065         }
2066     }
2067 
2068     /*
2069      * Fetch TX packet counters on current connection
2070      */
fetchPktcntNative(RssiPacketCountInfo info)2071     private void fetchPktcntNative(RssiPacketCountInfo info) {
2072         String pktcntPoll = mWifiNative.pktcntPoll();
2073 
2074         if (pktcntPoll != null) {
2075             String[] lines = pktcntPoll.split("\n");
2076             for (String line : lines) {
2077                 String[] prop = line.split("=");
2078                 if (prop.length < 2) continue;
2079                 try {
2080                     if (prop[0].equals("TXGOOD")) {
2081                         info.txgood = Integer.parseInt(prop[1]);
2082                     } else if (prop[0].equals("TXBAD")) {
2083                         info.txbad = Integer.parseInt(prop[1]);
2084                     }
2085                 } catch (NumberFormatException e) {
2086                     //Ignore
2087                 }
2088             }
2089         }
2090     }
2091 
2092     /**
2093      * Updates mLinkProperties by merging information from various sources.
2094      *
2095      * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
2096      * netlink, static configuration, ...). When one of these sources of information has updated
2097      * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
2098      * information that came from other sources. Instead, when one of those sources has new
2099      * information, we update the object that tracks the information from that source and then
2100      * call this method to apply the change to mLinkProperties.
2101      *
2102      * The information in mLinkProperties is currently obtained as follows:
2103      * - Interface name: set in the constructor.
2104      * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver.
2105      * - IPv4 routes, DNS servers, and domains: DHCP.
2106      * - HTTP proxy: the wifi config store.
2107      */
updateLinkProperties()2108     private void updateLinkProperties() {
2109         LinkProperties newLp = new LinkProperties();
2110 
2111         // Interface name and proxy are locally configured.
2112         newLp.setInterfaceName(mInterfaceName);
2113         newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
2114 
2115         // IPv4 and IPv6 addresses come from netlink.
2116         newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses());
2117 
2118         // For now, routing and DNS only come from DHCP or static configuration. In the future,
2119         // we'll need to merge IPv6 DNS servers and domains coming from netlink.
2120         synchronized (mDhcpResultsLock) {
2121             // Even when we're using static configuration, we don't need to look at the config
2122             // store, because static IP configuration also populates mDhcpResults.
2123             if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
2124                 LinkProperties lp = mDhcpResults.linkProperties;
2125                 for (RouteInfo route: lp.getRoutes()) {
2126                     newLp.addRoute(route);
2127                 }
2128                 for (InetAddress dns: lp.getDnses()) {
2129                     newLp.addDns(dns);
2130                 }
2131                 newLp.setDomains(lp.getDomains());
2132             }
2133         }
2134 
2135         // If anything has changed, and we're already connected, send out a notification.
2136         // If we're still connecting, apps will be notified when we connect.
2137         if (!newLp.equals(mLinkProperties)) {
2138             if (DBG) {
2139                 log("Link configuration changed for netId: " + mLastNetworkId
2140                         + " old: " + mLinkProperties + "new: " + newLp);
2141             }
2142             mLinkProperties = newLp;
2143             if (getNetworkDetailedState() == DetailedState.CONNECTED) {
2144                 sendLinkConfigurationChangedBroadcast();
2145             }
2146         }
2147     }
2148 
2149     /**
2150      * Clears all our link properties.
2151      */
clearLinkProperties()2152     private void clearLinkProperties() {
2153         // If the network used DHCP, clear the LinkProperties we stored in the config store.
2154         if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
2155             mWifiConfigStore.clearLinkProperties(mLastNetworkId);
2156         }
2157 
2158         // Clear the link properties obtained from DHCP and netlink.
2159         synchronized(mDhcpResultsLock) {
2160             if (mDhcpResults != null && mDhcpResults.linkProperties != null) {
2161                 mDhcpResults.linkProperties.clear();
2162             }
2163         }
2164         mNetlinkLinkProperties.clear();
2165 
2166         // Now clear the merged link properties.
2167         mLinkProperties.clear();
2168     }
2169 
getMaxDhcpRetries()2170     private int getMaxDhcpRetries() {
2171         return Settings.Global.getInt(mContext.getContentResolver(),
2172                                       Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
2173                                       DEFAULT_MAX_DHCP_RETRIES);
2174     }
2175 
sendScanResultsAvailableBroadcast()2176     private void sendScanResultsAvailableBroadcast() {
2177         noteScanEnd();
2178         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
2179         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2180         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2181     }
2182 
sendRssiChangeBroadcast(final int newRssi)2183     private void sendRssiChangeBroadcast(final int newRssi) {
2184         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
2185         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2186         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
2187         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2188     }
2189 
sendNetworkStateChangeBroadcast(String bssid)2190     private void sendNetworkStateChangeBroadcast(String bssid) {
2191         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
2192         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2193         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
2194         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
2195         if (bssid != null)
2196             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
2197         if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
2198                 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
2199             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
2200         }
2201         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2202     }
2203 
sendLinkConfigurationChangedBroadcast()2204     private void sendLinkConfigurationChangedBroadcast() {
2205         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
2206         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2207         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
2208         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2209     }
2210 
sendSupplicantConnectionChangedBroadcast(boolean connected)2211     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
2212         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
2213         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2214         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
2215         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2216     }
2217 
2218     /**
2219      * Record the detailed state of a network.
2220      * @param state the new {@code DetailedState}
2221      */
setNetworkDetailedState(NetworkInfo.DetailedState state)2222     private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
2223         if (DBG) {
2224             log("setDetailed state, old ="
2225                     + mNetworkInfo.getDetailedState() + " and new state=" + state);
2226         }
2227 
2228         if (state != mNetworkInfo.getDetailedState()) {
2229             mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
2230         }
2231     }
2232 
getNetworkDetailedState()2233     private DetailedState getNetworkDetailedState() {
2234         return mNetworkInfo.getDetailedState();
2235     }
2236 
2237 
handleSupplicantStateChange(Message message)2238     private SupplicantState handleSupplicantStateChange(Message message) {
2239         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2240         SupplicantState state = stateChangeResult.state;
2241         // Supplicant state change
2242         // [31-13] Reserved for future use
2243         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
2244         // 50023 supplicant_state_changed (custom|1|5)
2245         mWifiInfo.setSupplicantState(state);
2246         // Network id is only valid when we start connecting
2247         if (SupplicantState.isConnecting(state)) {
2248             mWifiInfo.setNetworkId(stateChangeResult.networkId);
2249         } else {
2250             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2251         }
2252 
2253         mWifiInfo.setBSSID(stateChangeResult.BSSID);
2254         mWifiInfo.setSSID(stateChangeResult.wifiSsid);
2255 
2256         mSupplicantStateTracker.sendMessage(Message.obtain(message));
2257 
2258         return state;
2259     }
2260 
2261     /**
2262      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
2263      * using the interface, stopping DHCP & disabling interface
2264      */
handleNetworkDisconnect()2265     private void handleNetworkDisconnect() {
2266         if (DBG) log("Stopping DHCP and clearing IP");
2267 
2268         stopDhcp();
2269 
2270         try {
2271             mNwService.clearInterfaceAddresses(mInterfaceName);
2272             mNwService.disableIpv6(mInterfaceName);
2273         } catch (Exception e) {
2274             loge("Failed to clear addresses or disable ipv6" + e);
2275         }
2276 
2277         /* Reset data structures */
2278         mWifiInfo.setInetAddress(null);
2279         mWifiInfo.setBSSID(null);
2280         mWifiInfo.setSSID(null);
2281         mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2282         mWifiInfo.setRssi(MIN_RSSI);
2283         mWifiInfo.setLinkSpeed(-1);
2284         mWifiInfo.setMeteredHint(false);
2285 
2286         setNetworkDetailedState(DetailedState.DISCONNECTED);
2287         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
2288 
2289         /* Clear network properties */
2290         clearLinkProperties();
2291 
2292         /* send event to CM & network change broadcast */
2293         sendNetworkStateChangeBroadcast(mLastBssid);
2294 
2295         mLastBssid= null;
2296         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2297     }
2298 
handleSupplicantConnectionLoss()2299     private void handleSupplicantConnectionLoss() {
2300         /* Socket connection can be lost when we do a graceful shutdown
2301         * or when the driver is hung. Ensure supplicant is stopped here.
2302         */
2303         mWifiMonitor.killSupplicant(mP2pSupported);
2304         sendSupplicantConnectionChangedBroadcast(false);
2305         setWifiState(WIFI_STATE_DISABLED);
2306     }
2307 
handlePreDhcpSetup()2308     void handlePreDhcpSetup() {
2309         mDhcpActive = true;
2310         if (!mBluetoothConnectionActive) {
2311             /*
2312              * There are problems setting the Wi-Fi driver's power
2313              * mode to active when bluetooth coexistence mode is
2314              * enabled or sense.
2315              * <p>
2316              * We set Wi-Fi to active mode when
2317              * obtaining an IP address because we've found
2318              * compatibility issues with some routers with low power
2319              * mode.
2320              * <p>
2321              * In order for this active power mode to properly be set,
2322              * we disable coexistence mode until we're done with
2323              * obtaining an IP address.  One exception is if we
2324              * are currently connected to a headset, since disabling
2325              * coexistence would interrupt that connection.
2326              */
2327             // Disable the coexistence mode
2328             mWifiNative.setBluetoothCoexistenceMode(
2329                     mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
2330         }
2331 
2332         /* Disable power save and suspend optimizations during DHCP */
2333         // Note: The order here is important for now. Brcm driver changes
2334         // power settings when we control suspend mode optimizations.
2335         // TODO: Remove this comment when the driver is fixed.
2336         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
2337         mWifiNative.setPowerSave(false);
2338 
2339         stopBatchedScan();
2340 
2341         /* P2p discovery breaks dhcp, shut it down in order to get through this */
2342         Message msg = new Message();
2343         msg.what = WifiP2pService.BLOCK_DISCOVERY;
2344         msg.arg1 = WifiP2pService.ENABLED;
2345         msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;
2346         msg.obj = mDhcpStateMachine;
2347         mWifiP2pChannel.sendMessage(msg);
2348     }
2349 
2350 
startDhcp()2351     void startDhcp() {
2352         if (mDhcpStateMachine == null) {
2353             mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
2354                     mContext, WifiStateMachine.this, mInterfaceName);
2355 
2356         }
2357         mDhcpStateMachine.registerForPreDhcpNotification();
2358         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
2359     }
2360 
stopDhcp()2361     void stopDhcp() {
2362         if (mDhcpStateMachine != null) {
2363             /* In case we were in middle of DHCP operation restore back powermode */
2364             handlePostDhcpSetup();
2365             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
2366         }
2367     }
2368 
handlePostDhcpSetup()2369     void handlePostDhcpSetup() {
2370         /* Restore power save and suspend optimizations */
2371         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
2372         mWifiNative.setPowerSave(true);
2373 
2374         mWifiP2pChannel.sendMessage(WifiP2pService.BLOCK_DISCOVERY, WifiP2pService.DISABLED);
2375 
2376         // Set the coexistence mode back to its default value
2377         mWifiNative.setBluetoothCoexistenceMode(
2378                 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
2379 
2380         mDhcpActive = false;
2381 
2382         startBatchedScan();
2383     }
2384 
handleSuccessfulIpConfiguration(DhcpResults dhcpResults)2385     private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
2386         mLastSignalLevel = -1; // force update of signal strength
2387         mReconnectCount = 0; //Reset IP failure tracking
2388         synchronized (mDhcpResultsLock) {
2389             mDhcpResults = dhcpResults;
2390         }
2391         LinkProperties linkProperties = dhcpResults.linkProperties;
2392         mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties));
2393         InetAddress addr = null;
2394         Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator();
2395         if (addrs.hasNext()) {
2396             addr = addrs.next();
2397         }
2398         mWifiInfo.setInetAddress(addr);
2399         mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
2400         updateLinkProperties();
2401     }
2402 
handleFailedIpConfiguration()2403     private void handleFailedIpConfiguration() {
2404         loge("IP configuration failed");
2405 
2406         mWifiInfo.setInetAddress(null);
2407         mWifiInfo.setMeteredHint(false);
2408         /**
2409          * If we've exceeded the maximum number of retries for DHCP
2410          * to a given network, disable the network
2411          */
2412         int maxRetries = getMaxDhcpRetries();
2413         // maxRetries == 0 means keep trying forever
2414         if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
2415             loge("Failed " +
2416                     mReconnectCount + " times, Disabling " + mLastNetworkId);
2417             mWifiConfigStore.disableNetwork(mLastNetworkId,
2418                     WifiConfiguration.DISABLED_DHCP_FAILURE);
2419             mReconnectCount = 0;
2420         }
2421 
2422         /* DHCP times out after about 30 seconds, we do a
2423          * disconnect and an immediate reconnect to try again
2424          */
2425         mWifiNative.disconnect();
2426         mWifiNative.reconnect();
2427     }
2428 
2429     /* Current design is to not set the config on a running hostapd but instead
2430      * stop and start tethering when user changes config on a running access point
2431      *
2432      * TODO: Add control channel setup through hostapd that allows changing config
2433      * on a running daemon
2434      */
startSoftApWithConfig(final WifiConfiguration config)2435     private void startSoftApWithConfig(final WifiConfiguration config) {
2436         // start hostapd on a seperate thread
2437         new Thread(new Runnable() {
2438             public void run() {
2439                 try {
2440                     mNwService.startAccessPoint(config, mInterfaceName);
2441                 } catch (Exception e) {
2442                     loge("Exception in softap start " + e);
2443                     try {
2444                         mNwService.stopAccessPoint(mInterfaceName);
2445                         mNwService.startAccessPoint(config, mInterfaceName);
2446                     } catch (Exception e1) {
2447                         loge("Exception in softap re-start " + e1);
2448                         sendMessage(CMD_START_AP_FAILURE);
2449                         return;
2450                     }
2451                 }
2452                 if (DBG) log("Soft AP start successful");
2453                 sendMessage(CMD_START_AP_SUCCESS);
2454             }
2455         }).start();
2456     }
2457 
2458     /********************************************************
2459      * HSM states
2460      *******************************************************/
2461 
2462     class DefaultState extends State {
2463         @Override
processMessage(Message message)2464         public boolean processMessage(Message message) {
2465             switch (message.what) {
2466                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
2467                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
2468                         mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
2469                     } else {
2470                         loge("WifiP2pService connection failure, error=" + message.arg1);
2471                     }
2472                     break;
2473                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
2474                     loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
2475                     //TODO: Re-establish connection to state machine after a delay
2476                     //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
2477                     break;
2478                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2479                     mBluetoothConnectionActive = (message.arg1 !=
2480                             BluetoothAdapter.STATE_DISCONNECTED);
2481                     break;
2482                     /* Synchronous call returns */
2483                 case CMD_PING_SUPPLICANT:
2484                 case CMD_ENABLE_NETWORK:
2485                 case CMD_ADD_OR_UPDATE_NETWORK:
2486                 case CMD_REMOVE_NETWORK:
2487                 case CMD_SAVE_CONFIG:
2488                     replyToMessage(message, message.what, FAILURE);
2489                     break;
2490                 case CMD_GET_CONFIGURED_NETWORKS:
2491                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
2492                     break;
2493                 case CMD_ENABLE_RSSI_POLL:
2494                     mEnableRssiPolling = (message.arg1 == 1);
2495                     break;
2496                 case CMD_ENABLE_BACKGROUND_SCAN:
2497                     mEnableBackgroundScan = (message.arg1 == 1);
2498                     break;
2499                 case CMD_SET_HIGH_PERF_MODE:
2500                     if (message.arg1 == 1) {
2501                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
2502                     } else {
2503                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
2504                     }
2505                     break;
2506                 case CMD_BOOT_COMPLETED:
2507                     String countryCode = mPersistedCountryCode;
2508                     if (TextUtils.isEmpty(countryCode) == false) {
2509                         Settings.Global.putString(mContext.getContentResolver(),
2510                                 Settings.Global.WIFI_COUNTRY_CODE,
2511                                 countryCode);
2512                         // it may be that the state transition that should send this info
2513                         // to the driver happened between mPersistedCountryCode getting set
2514                         // and now, so simply persisting it here would mean we have sent
2515                         // nothing to the driver.  Send the cmd so it might be set now.
2516                         int sequenceNum = mCountryCodeSequence.incrementAndGet();
2517                         sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE,
2518                                 sequenceNum, 0, countryCode);
2519                     }
2520                     break;
2521                 case CMD_SET_BATCHED_SCAN:
2522                     recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj);
2523                     break;
2524                 case CMD_POLL_BATCHED_SCAN:
2525                     handleBatchedScanPollRequest();
2526                     break;
2527                 case CMD_START_NEXT_BATCHED_SCAN:
2528                     startNextBatchedScan();
2529                     break;
2530                     /* Discard */
2531                 case CMD_START_SCAN:
2532                 case CMD_START_SUPPLICANT:
2533                 case CMD_STOP_SUPPLICANT:
2534                 case CMD_STOP_SUPPLICANT_FAILED:
2535                 case CMD_START_DRIVER:
2536                 case CMD_STOP_DRIVER:
2537                 case CMD_DELAYED_STOP_DRIVER:
2538                 case CMD_DRIVER_START_TIMED_OUT:
2539                 case CMD_CAPTIVE_CHECK_COMPLETE:
2540                 case CMD_START_AP:
2541                 case CMD_START_AP_SUCCESS:
2542                 case CMD_START_AP_FAILURE:
2543                 case CMD_STOP_AP:
2544                 case CMD_TETHER_STATE_CHANGE:
2545                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
2546                 case CMD_DISCONNECT:
2547                 case CMD_RECONNECT:
2548                 case CMD_REASSOCIATE:
2549                 case CMD_RELOAD_TLS_AND_RECONNECT:
2550                 case WifiMonitor.SUP_CONNECTION_EVENT:
2551                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2552                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
2553                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2554                 case WifiMonitor.SCAN_RESULTS_EVENT:
2555                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2556                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2557                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2558                 case WifiMonitor.WPS_OVERLAP_EVENT:
2559                 case CMD_BLACKLIST_NETWORK:
2560                 case CMD_CLEAR_BLACKLIST:
2561                 case CMD_SET_OPERATIONAL_MODE:
2562                 case CMD_SET_COUNTRY_CODE:
2563                 case CMD_SET_FREQUENCY_BAND:
2564                 case CMD_RSSI_POLL:
2565                 case CMD_ENABLE_ALL_NETWORKS:
2566                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2567                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2568                 /* Handled by WifiApConfigStore */
2569                 case CMD_SET_AP_CONFIG:
2570                 case CMD_SET_AP_CONFIG_COMPLETED:
2571                 case CMD_REQUEST_AP_CONFIG:
2572                 case CMD_RESPONSE_AP_CONFIG:
2573                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
2574                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
2575                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
2576                 case CMD_DISABLE_P2P_RSP:
2577                     break;
2578                 case DhcpStateMachine.CMD_ON_QUIT:
2579                     mDhcpStateMachine = null;
2580                     break;
2581                 case CMD_SET_SUSPEND_OPT_ENABLED:
2582                     if (message.arg1 == 1) {
2583                         mSuspendWakeLock.release();
2584                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
2585                     } else {
2586                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
2587                     }
2588                     break;
2589                 case WifiMonitor.DRIVER_HUNG_EVENT:
2590                     setSupplicantRunning(false);
2591                     setSupplicantRunning(true);
2592                     break;
2593                 case WifiManager.CONNECT_NETWORK:
2594                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
2595                             WifiManager.BUSY);
2596                     break;
2597                 case WifiManager.FORGET_NETWORK:
2598                     replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
2599                             WifiManager.BUSY);
2600                     break;
2601                 case WifiManager.SAVE_NETWORK:
2602                     replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
2603                             WifiManager.BUSY);
2604                     break;
2605                 case WifiManager.START_WPS:
2606                     replyToMessage(message, WifiManager.WPS_FAILED,
2607                             WifiManager.BUSY);
2608                     break;
2609                 case WifiManager.CANCEL_WPS:
2610                     replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
2611                             WifiManager.BUSY);
2612                     break;
2613                 case WifiManager.DISABLE_NETWORK:
2614                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
2615                             WifiManager.BUSY);
2616                     break;
2617                 case WifiManager.RSSI_PKTCNT_FETCH:
2618                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
2619                             WifiManager.BUSY);
2620                     break;
2621                 case WifiP2pService.P2P_CONNECTION_CHANGED:
2622                     NetworkInfo info = (NetworkInfo) message.obj;
2623                     mP2pConnected.set(info.isConnected());
2624                     break;
2625                 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
2626                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
2627                     replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
2628                     break;
2629                 case CMD_IP_ADDRESS_UPDATED:
2630                     // addLinkAddress is a no-op if called more than once with the same address.
2631                     if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) {
2632                         updateLinkProperties();
2633                     }
2634                     break;
2635                 case CMD_IP_ADDRESS_REMOVED:
2636                     if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) {
2637                         updateLinkProperties();
2638                     }
2639                     break;
2640                 default:
2641                     loge("Error! unhandled message" + message);
2642                     break;
2643             }
2644             return HANDLED;
2645         }
2646     }
2647 
2648     class InitialState extends State {
2649         @Override
enter()2650         public void enter() {
2651             mWifiNative.unloadDriver();
2652 
2653             if (mWifiP2pChannel == null) {
2654                 mWifiP2pChannel = new AsyncChannel();
2655                 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
2656             }
2657 
2658             if (mWifiApConfigChannel == null) {
2659                 mWifiApConfigChannel = new AsyncChannel();
2660                 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
2661                         mContext, getHandler());
2662                 wifiApConfigStore.loadApConfiguration();
2663                 mWifiApConfigChannel.connectSync(mContext, getHandler(),
2664                         wifiApConfigStore.getMessenger());
2665             }
2666         }
2667         @Override
processMessage(Message message)2668         public boolean processMessage(Message message) {
2669             switch (message.what) {
2670                 case CMD_START_SUPPLICANT:
2671                     if (mWifiNative.loadDriver()) {
2672                         try {
2673                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
2674                         } catch (Exception e) {
2675                             loge("Failed to reload STA firmware " + e);
2676                             // continue
2677                         }
2678 
2679                         try {
2680                             // A runtime crash can leave the interface up and
2681                             // this affects connectivity when supplicant starts up.
2682                             // Ensure interface is down before a supplicant start.
2683                             mNwService.setInterfaceDown(mInterfaceName);
2684                             // Set privacy extensions
2685                             mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
2686 
2687                            // IPv6 is enabled only as long as access point is connected since:
2688                            // - IPv6 addresses and routes stick around after disconnection
2689                            // - kernel is unaware when connected and fails to start IPv6 negotiation
2690                            // - kernel can start autoconfiguration when 802.1x is not complete
2691                             mNwService.disableIpv6(mInterfaceName);
2692                         } catch (RemoteException re) {
2693                             loge("Unable to change interface settings: " + re);
2694                         } catch (IllegalStateException ie) {
2695                             loge("Unable to change interface settings: " + ie);
2696                         }
2697 
2698                        /* Stop a running supplicant after a runtime restart
2699                         * Avoids issues with drivers that do not handle interface down
2700                         * on a running supplicant properly.
2701                         */
2702                         mWifiMonitor.killSupplicant(mP2pSupported);
2703                         if(mWifiNative.startSupplicant(mP2pSupported)) {
2704                             setWifiState(WIFI_STATE_ENABLING);
2705                             if (DBG) log("Supplicant start successful");
2706                             mWifiMonitor.startMonitoring();
2707                             transitionTo(mSupplicantStartingState);
2708                         } else {
2709                             loge("Failed to start supplicant!");
2710                         }
2711                     } else {
2712                         loge("Failed to load driver");
2713                     }
2714                     break;
2715                 case CMD_START_AP:
2716                     if (mWifiNative.loadDriver()) {
2717                         setWifiApState(WIFI_AP_STATE_ENABLING);
2718                         transitionTo(mSoftApStartingState);
2719                     } else {
2720                         loge("Failed to load driver for softap");
2721                     }
2722                 default:
2723                     return NOT_HANDLED;
2724             }
2725             return HANDLED;
2726         }
2727     }
2728 
2729     class SupplicantStartingState extends State {
initializeWpsDetails()2730         private void initializeWpsDetails() {
2731             String detail;
2732             detail = SystemProperties.get("ro.product.name", "");
2733             if (!mWifiNative.setDeviceName(detail)) {
2734                 loge("Failed to set device name " +  detail);
2735             }
2736             detail = SystemProperties.get("ro.product.manufacturer", "");
2737             if (!mWifiNative.setManufacturer(detail)) {
2738                 loge("Failed to set manufacturer " + detail);
2739             }
2740             detail = SystemProperties.get("ro.product.model", "");
2741             if (!mWifiNative.setModelName(detail)) {
2742                 loge("Failed to set model name " + detail);
2743             }
2744             detail = SystemProperties.get("ro.product.model", "");
2745             if (!mWifiNative.setModelNumber(detail)) {
2746                 loge("Failed to set model number " + detail);
2747             }
2748             detail = SystemProperties.get("ro.serialno", "");
2749             if (!mWifiNative.setSerialNumber(detail)) {
2750                 loge("Failed to set serial number " + detail);
2751             }
2752             if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
2753                 loge("Failed to set WPS config methods");
2754             }
2755             if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
2756                 loge("Failed to set primary device type " + mPrimaryDeviceType);
2757             }
2758         }
2759 
2760         @Override
processMessage(Message message)2761         public boolean processMessage(Message message) {
2762             switch(message.what) {
2763                 case WifiMonitor.SUP_CONNECTION_EVENT:
2764                     if (DBG) log("Supplicant connection established");
2765                     setWifiState(WIFI_STATE_ENABLED);
2766                     mSupplicantRestartCount = 0;
2767                     /* Reset the supplicant state to indicate the supplicant
2768                      * state is not known at this time */
2769                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2770                     /* Initialize data structures */
2771                     mLastBssid = null;
2772                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2773                     mLastSignalLevel = -1;
2774 
2775                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
2776                     mWifiConfigStore.loadAndEnableAllNetworks();
2777                     initializeWpsDetails();
2778 
2779                     sendSupplicantConnectionChangedBroadcast(true);
2780                     transitionTo(mDriverStartedState);
2781                     break;
2782                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2783                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2784                         loge("Failed to setup control channel, restart supplicant");
2785                         mWifiMonitor.killSupplicant(mP2pSupported);
2786                         transitionTo(mInitialState);
2787                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2788                     } else {
2789                         loge("Failed " + mSupplicantRestartCount +
2790                                 " times to start supplicant, unload driver");
2791                         mSupplicantRestartCount = 0;
2792                         setWifiState(WIFI_STATE_UNKNOWN);
2793                         transitionTo(mInitialState);
2794                     }
2795                     break;
2796                 case CMD_START_SUPPLICANT:
2797                 case CMD_STOP_SUPPLICANT:
2798                 case CMD_START_AP:
2799                 case CMD_STOP_AP:
2800                 case CMD_START_DRIVER:
2801                 case CMD_STOP_DRIVER:
2802                 case CMD_SET_OPERATIONAL_MODE:
2803                 case CMD_SET_COUNTRY_CODE:
2804                 case CMD_SET_FREQUENCY_BAND:
2805                 case CMD_START_PACKET_FILTERING:
2806                 case CMD_STOP_PACKET_FILTERING:
2807                     deferMessage(message);
2808                     break;
2809                 default:
2810                     return NOT_HANDLED;
2811             }
2812             return HANDLED;
2813         }
2814     }
2815 
2816     class SupplicantStartedState extends State {
2817         @Override
enter()2818         public void enter() {
2819             /* Wifi is available as long as we have a connection to supplicant */
2820             mNetworkInfo.setIsAvailable(true);
2821 
2822             int defaultInterval = mContext.getResources().getInteger(
2823                     R.integer.config_wifi_supplicant_scan_interval);
2824 
2825             mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
2826                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2827                     defaultInterval);
2828 
2829             mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
2830         }
2831         @Override
processMessage(Message message)2832         public boolean processMessage(Message message) {
2833             switch(message.what) {
2834                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
2835                     if (mP2pSupported) {
2836                         transitionTo(mWaitForP2pDisableState);
2837                     } else {
2838                         transitionTo(mSupplicantStoppingState);
2839                     }
2840                     break;
2841                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
2842                     loge("Connection lost, restart supplicant");
2843                     handleSupplicantConnectionLoss();
2844                     handleNetworkDisconnect();
2845                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2846                     if (mP2pSupported) {
2847                         transitionTo(mWaitForP2pDisableState);
2848                     } else {
2849                         transitionTo(mInitialState);
2850                     }
2851                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2852                     break;
2853                 case WifiMonitor.SCAN_RESULTS_EVENT:
2854                     setScanResults();
2855                     sendScanResultsAvailableBroadcast();
2856                     mScanResultIsPending = false;
2857                     break;
2858                 case CMD_PING_SUPPLICANT:
2859                     boolean ok = mWifiNative.ping();
2860                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2861                     break;
2862                     /* Cannot start soft AP while in client mode */
2863                 case CMD_START_AP:
2864                     loge("Failed to start soft AP with a running supplicant");
2865                     setWifiApState(WIFI_AP_STATE_FAILED);
2866                     break;
2867                 case CMD_SET_OPERATIONAL_MODE:
2868                     mOperationalMode = message.arg1;
2869                     break;
2870                 default:
2871                     return NOT_HANDLED;
2872             }
2873             return HANDLED;
2874         }
2875 
2876         @Override
exit()2877         public void exit() {
2878             mNetworkInfo.setIsAvailable(false);
2879         }
2880     }
2881 
2882     class SupplicantStoppingState extends State {
2883         @Override
enter()2884         public void enter() {
2885             /* Send any reset commands to supplicant before shutting it down */
2886             handleNetworkDisconnect();
2887             if (mDhcpStateMachine != null) {
2888                 mDhcpStateMachine.doQuit();
2889             }
2890 
2891             if (DBG) log("stopping supplicant");
2892             mWifiMonitor.stopSupplicant();
2893 
2894             /* Send ourselves a delayed message to indicate failure after a wait time */
2895             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
2896                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
2897             setWifiState(WIFI_STATE_DISABLING);
2898             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2899         }
2900         @Override
processMessage(Message message)2901         public boolean processMessage(Message message) {
2902             switch(message.what) {
2903                 case WifiMonitor.SUP_CONNECTION_EVENT:
2904                     loge("Supplicant connection received while stopping");
2905                     break;
2906                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2907                     if (DBG) log("Supplicant connection lost");
2908                     handleSupplicantConnectionLoss();
2909                     transitionTo(mInitialState);
2910                     break;
2911                 case CMD_STOP_SUPPLICANT_FAILED:
2912                     if (message.arg1 == mSupplicantStopFailureToken) {
2913                         loge("Timed out on a supplicant stop, kill and proceed");
2914                         handleSupplicantConnectionLoss();
2915                         transitionTo(mInitialState);
2916                     }
2917                     break;
2918                 case CMD_START_SUPPLICANT:
2919                 case CMD_STOP_SUPPLICANT:
2920                 case CMD_START_AP:
2921                 case CMD_STOP_AP:
2922                 case CMD_START_DRIVER:
2923                 case CMD_STOP_DRIVER:
2924                 case CMD_SET_OPERATIONAL_MODE:
2925                 case CMD_SET_COUNTRY_CODE:
2926                 case CMD_SET_FREQUENCY_BAND:
2927                 case CMD_START_PACKET_FILTERING:
2928                 case CMD_STOP_PACKET_FILTERING:
2929                     deferMessage(message);
2930                     break;
2931                 default:
2932                     return NOT_HANDLED;
2933             }
2934             return HANDLED;
2935         }
2936     }
2937 
2938     class DriverStartingState extends State {
2939         private int mTries;
2940         @Override
enter()2941         public void enter() {
2942             mTries = 1;
2943             /* Send ourselves a delayed message to start driver a second time */
2944             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2945                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2946         }
2947         @Override
processMessage(Message message)2948         public boolean processMessage(Message message) {
2949             switch(message.what) {
2950                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2951                     SupplicantState state = handleSupplicantStateChange(message);
2952                     /* If suplicant is exiting out of INTERFACE_DISABLED state into
2953                      * a state that indicates driver has started, it is ready to
2954                      * receive driver commands
2955                      */
2956                     if (SupplicantState.isDriverActive(state)) {
2957                         transitionTo(mDriverStartedState);
2958                     }
2959                     break;
2960                 case CMD_DRIVER_START_TIMED_OUT:
2961                     if (message.arg1 == mDriverStartToken) {
2962                         if (mTries >= 2) {
2963                             loge("Failed to start driver after " + mTries);
2964                             transitionTo(mDriverStoppedState);
2965                         } else {
2966                             loge("Driver start failed, retrying");
2967                             mWakeLock.acquire();
2968                             mWifiNative.startDriver();
2969                             mWakeLock.release();
2970 
2971                             ++mTries;
2972                             /* Send ourselves a delayed message to start driver again */
2973                             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2974                                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2975                         }
2976                     }
2977                     break;
2978                     /* Queue driver commands & connection events */
2979                 case CMD_START_DRIVER:
2980                 case CMD_STOP_DRIVER:
2981                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
2982                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2983                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2984                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
2985                 case WifiMonitor.WPS_OVERLAP_EVENT:
2986                 case CMD_SET_COUNTRY_CODE:
2987                 case CMD_SET_FREQUENCY_BAND:
2988                 case CMD_START_PACKET_FILTERING:
2989                 case CMD_STOP_PACKET_FILTERING:
2990                 case CMD_START_SCAN:
2991                 case CMD_DISCONNECT:
2992                 case CMD_REASSOCIATE:
2993                 case CMD_RECONNECT:
2994                     deferMessage(message);
2995                     break;
2996                 default:
2997                     return NOT_HANDLED;
2998             }
2999             return HANDLED;
3000         }
3001     }
3002 
3003     class DriverStartedState extends State {
3004         @Override
enter()3005         public void enter() {
3006             mIsRunning = true;
3007             mInDelayedStop = false;
3008             mDelayedStopCounter++;
3009             updateBatteryWorkSource(null);
3010             /**
3011              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
3012              * When this mode is on, some of the low-level scan parameters used by the
3013              * driver are changed to reduce interference with bluetooth
3014              */
3015             mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
3016             /* set country code */
3017             setCountryCode();
3018             /* set frequency band of operation */
3019             setFrequencyBand();
3020             /* initialize network state */
3021             setNetworkDetailedState(DetailedState.DISCONNECTED);
3022 
3023             /* Remove any filtering on Multicast v6 at start */
3024             mWifiNative.stopFilteringMulticastV6Packets();
3025 
3026             /* Reset Multicast v4 filtering state */
3027             if (mFilteringMulticastV4Packets.get()) {
3028                 mWifiNative.startFilteringMulticastV4Packets();
3029             } else {
3030                 mWifiNative.stopFilteringMulticastV4Packets();
3031             }
3032 
3033             mDhcpActive = false;
3034 
3035             startBatchedScan();
3036 
3037             if (mOperationalMode != CONNECT_MODE) {
3038                 mWifiNative.disconnect();
3039                 mWifiConfigStore.disableAllNetworks();
3040                 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
3041                     setWifiState(WIFI_STATE_DISABLED);
3042                 }
3043                 transitionTo(mScanModeState);
3044             } else {
3045                 /* Driver stop may have disabled networks, enable right after start */
3046                 mWifiConfigStore.enableAllNetworks();
3047 
3048                 if (DBG) log("Attempting to reconnect to wifi network ..");
3049                 mWifiNative.reconnect();
3050 
3051                 // Status pulls in the current supplicant state and network connection state
3052                 // events over the monitor connection. This helps framework sync up with
3053                 // current supplicant state
3054                 mWifiNative.status();
3055                 transitionTo(mDisconnectedState);
3056             }
3057 
3058             // We may have missed screen update at boot
3059             if (mScreenBroadcastReceived.get() == false) {
3060                 PowerManager powerManager = (PowerManager)mContext.getSystemService(
3061                         Context.POWER_SERVICE);
3062                 handleScreenStateChanged(powerManager.isScreenOn());
3063             } else {
3064                 // Set the right suspend mode settings
3065                 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
3066                         && mUserWantsSuspendOpt.get());
3067             }
3068             mWifiNative.setPowerSave(true);
3069 
3070             if (mP2pSupported) {
3071                 if (mOperationalMode == CONNECT_MODE) {
3072                     mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
3073                 } else {
3074                     // P2P statemachine starts in disabled state, and is not enabled until
3075                     // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
3076                     // keep it disabled.
3077                 }
3078             }
3079 
3080             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
3081             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3082             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
3083             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3084         }
3085 
3086         @Override
processMessage(Message message)3087         public boolean processMessage(Message message) {
3088             switch(message.what) {
3089                 case CMD_START_SCAN:
3090                     noteScanStart(message.arg1, (WorkSource) message.obj);
3091                     startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
3092                     break;
3093                 case CMD_SET_BATCHED_SCAN:
3094                     if (recordBatchedScanSettings(message.arg1, message.arg2,
3095                             (Bundle)message.obj)) {
3096                         if (mBatchedScanSettings != null) {
3097                             startBatchedScan();
3098                         } else {
3099                             stopBatchedScan();
3100                         }
3101                     }
3102                     break;
3103                 case CMD_SET_COUNTRY_CODE:
3104                     String country = (String) message.obj;
3105                     final boolean persist = (message.arg2 == 1);
3106                     final int sequence = message.arg1;
3107                     if (sequence != mCountryCodeSequence.get()) {
3108                         if (DBG) log("set country code ignored due to sequence num");
3109                         break;
3110                     }
3111                     if (DBG) log("set country code " + country);
3112                     if (persist) {
3113                         mPersistedCountryCode = country;
3114                         Settings.Global.putString(mContext.getContentResolver(),
3115                                 Settings.Global.WIFI_COUNTRY_CODE,
3116                                 country);
3117                     }
3118                     country = country.toUpperCase(Locale.ROOT);
3119                     if (mLastSetCountryCode == null
3120                             || country.equals(mLastSetCountryCode) == false) {
3121                         if (mWifiNative.setCountryCode(country)) {
3122                             mLastSetCountryCode = country;
3123                         } else {
3124                             loge("Failed to set country code " + country);
3125                         }
3126                     }
3127                     mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, country);
3128                     break;
3129                 case CMD_SET_FREQUENCY_BAND:
3130                     int band =  message.arg1;
3131                     if (DBG) log("set frequency band " + band);
3132                     if (mWifiNative.setBand(band)) {
3133                         mFrequencyBand.set(band);
3134                         // flush old data - like scan results
3135                         mWifiNative.bssFlush();
3136                         //Fetch the latest scan results when frequency band is set
3137                         startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
3138                     } else {
3139                         loge("Failed to set frequency band " + band);
3140                     }
3141                     break;
3142                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
3143                     mBluetoothConnectionActive = (message.arg1 !=
3144                             BluetoothAdapter.STATE_DISCONNECTED);
3145                     mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
3146                     break;
3147                 case CMD_STOP_DRIVER:
3148                     int mode = message.arg1;
3149 
3150                     /* Already doing a delayed stop */
3151                     if (mInDelayedStop) {
3152                         if (DBG) log("Already in delayed stop");
3153                         break;
3154                     }
3155                     /* disconnect right now, but leave the driver running for a bit */
3156                     mWifiConfigStore.disableAllNetworks();
3157 
3158                     mInDelayedStop = true;
3159                     mDelayedStopCounter++;
3160                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
3161 
3162                     /* send regular delayed shut down */
3163                     Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
3164                     driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
3165                     mDriverStopIntent = PendingIntent.getBroadcast(mContext,
3166                             DRIVER_STOP_REQUEST, driverStopIntent,
3167                             PendingIntent.FLAG_UPDATE_CURRENT);
3168 
3169                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
3170                             + mDriverStopDelayMs, mDriverStopIntent);
3171                     break;
3172                 case CMD_START_DRIVER:
3173                     if (mInDelayedStop) {
3174                         mInDelayedStop = false;
3175                         mDelayedStopCounter++;
3176                         mAlarmManager.cancel(mDriverStopIntent);
3177                         if (DBG) log("Delayed stop ignored due to start");
3178                         if (mOperationalMode == CONNECT_MODE) {
3179                             mWifiConfigStore.enableAllNetworks();
3180                         }
3181                     }
3182                     break;
3183                 case CMD_DELAYED_STOP_DRIVER:
3184                     if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
3185                     if (message.arg1 != mDelayedStopCounter) break;
3186                     if (getCurrentState() != mDisconnectedState) {
3187                         mWifiNative.disconnect();
3188                         handleNetworkDisconnect();
3189                     }
3190                     mWakeLock.acquire();
3191                     mWifiNative.stopDriver();
3192                     mWakeLock.release();
3193                     if (mP2pSupported) {
3194                         transitionTo(mWaitForP2pDisableState);
3195                     } else {
3196                         transitionTo(mDriverStoppingState);
3197                     }
3198                     break;
3199                 case CMD_START_PACKET_FILTERING:
3200                     if (message.arg1 == MULTICAST_V6) {
3201                         mWifiNative.startFilteringMulticastV6Packets();
3202                     } else if (message.arg1 == MULTICAST_V4) {
3203                         mWifiNative.startFilteringMulticastV4Packets();
3204                     } else {
3205                         loge("Illegal arugments to CMD_START_PACKET_FILTERING");
3206                     }
3207                     break;
3208                 case CMD_STOP_PACKET_FILTERING:
3209                     if (message.arg1 == MULTICAST_V6) {
3210                         mWifiNative.stopFilteringMulticastV6Packets();
3211                     } else if (message.arg1 == MULTICAST_V4) {
3212                         mWifiNative.stopFilteringMulticastV4Packets();
3213                     } else {
3214                         loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
3215                     }
3216                     break;
3217                 case CMD_SET_SUSPEND_OPT_ENABLED:
3218                     if (message.arg1 == 1) {
3219                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
3220                         mSuspendWakeLock.release();
3221                     } else {
3222                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
3223                     }
3224                     break;
3225                 case CMD_SET_HIGH_PERF_MODE:
3226                     if (message.arg1 == 1) {
3227                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
3228                     } else {
3229                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
3230                     }
3231                     break;
3232                 case CMD_ENABLE_TDLS:
3233                     if (message.obj != null) {
3234                         String remoteAddress = (String) message.obj;
3235                         boolean enable = (message.arg1 == 1);
3236                         mWifiNative.startTdls(remoteAddress, enable);
3237                     }
3238                     break;
3239                 default:
3240                     return NOT_HANDLED;
3241             }
3242             return HANDLED;
3243         }
3244         @Override
exit()3245         public void exit() {
3246             mIsRunning = false;
3247             updateBatteryWorkSource(null);
3248             mScanResults = new ArrayList<ScanResult>();
3249 
3250             stopBatchedScan();
3251 
3252             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
3253             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3254             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
3255             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3256             noteScanEnd(); // wrap up any pending request.
3257 
3258             mLastSetCountryCode = null;
3259         }
3260     }
3261 
3262     class WaitForP2pDisableState extends State {
3263         private State mTransitionToState;
3264         @Override
enter()3265         public void enter() {
3266             switch (getCurrentMessage().what) {
3267                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
3268                     mTransitionToState = mInitialState;
3269                     break;
3270                 case CMD_DELAYED_STOP_DRIVER:
3271                     mTransitionToState = mDriverStoppingState;
3272                     break;
3273                 case CMD_STOP_SUPPLICANT:
3274                     mTransitionToState = mSupplicantStoppingState;
3275                     break;
3276                 default:
3277                     mTransitionToState = mDriverStoppingState;
3278                     break;
3279             }
3280             mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
3281         }
3282         @Override
processMessage(Message message)3283         public boolean processMessage(Message message) {
3284             switch(message.what) {
3285                 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
3286                     transitionTo(mTransitionToState);
3287                     break;
3288                 /* Defer wifi start/shut and driver commands */
3289                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3290                 case CMD_START_SUPPLICANT:
3291                 case CMD_STOP_SUPPLICANT:
3292                 case CMD_START_AP:
3293                 case CMD_STOP_AP:
3294                 case CMD_START_DRIVER:
3295                 case CMD_STOP_DRIVER:
3296                 case CMD_SET_OPERATIONAL_MODE:
3297                 case CMD_SET_COUNTRY_CODE:
3298                 case CMD_SET_FREQUENCY_BAND:
3299                 case CMD_START_PACKET_FILTERING:
3300                 case CMD_STOP_PACKET_FILTERING:
3301                 case CMD_START_SCAN:
3302                 case CMD_DISCONNECT:
3303                 case CMD_REASSOCIATE:
3304                 case CMD_RECONNECT:
3305                     deferMessage(message);
3306                     break;
3307                 default:
3308                     return NOT_HANDLED;
3309             }
3310             return HANDLED;
3311         }
3312     }
3313 
3314     class DriverStoppingState extends State {
3315         @Override
processMessage(Message message)3316         public boolean processMessage(Message message) {
3317             switch(message.what) {
3318                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3319                     SupplicantState state = handleSupplicantStateChange(message);
3320                     if (state == SupplicantState.INTERFACE_DISABLED) {
3321                         transitionTo(mDriverStoppedState);
3322                     }
3323                     break;
3324                     /* Queue driver commands */
3325                 case CMD_START_DRIVER:
3326                 case CMD_STOP_DRIVER:
3327                 case CMD_SET_COUNTRY_CODE:
3328                 case CMD_SET_FREQUENCY_BAND:
3329                 case CMD_START_PACKET_FILTERING:
3330                 case CMD_STOP_PACKET_FILTERING:
3331                 case CMD_START_SCAN:
3332                 case CMD_DISCONNECT:
3333                 case CMD_REASSOCIATE:
3334                 case CMD_RECONNECT:
3335                     deferMessage(message);
3336                     break;
3337                 default:
3338                     return NOT_HANDLED;
3339             }
3340             return HANDLED;
3341         }
3342     }
3343 
3344     class DriverStoppedState extends State {
3345         @Override
processMessage(Message message)3346         public boolean processMessage(Message message) {
3347             switch (message.what) {
3348                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3349                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3350                     SupplicantState state = stateChangeResult.state;
3351                     // A WEXT bug means that we can be back to driver started state
3352                     // unexpectedly
3353                     if (SupplicantState.isDriverActive(state)) {
3354                         transitionTo(mDriverStartedState);
3355                     }
3356                     break;
3357                 case CMD_START_DRIVER:
3358                     mWakeLock.acquire();
3359                     mWifiNative.startDriver();
3360                     mWakeLock.release();
3361                     transitionTo(mDriverStartingState);
3362                     break;
3363                 default:
3364                     return NOT_HANDLED;
3365             }
3366             return HANDLED;
3367         }
3368     }
3369 
3370     class ScanModeState extends State {
3371         private int mLastOperationMode;
3372         @Override
enter()3373         public void enter() {
3374             mLastOperationMode = mOperationalMode;
3375         }
3376         @Override
processMessage(Message message)3377         public boolean processMessage(Message message) {
3378             switch(message.what) {
3379                 case CMD_SET_OPERATIONAL_MODE:
3380                     if (message.arg1 == CONNECT_MODE) {
3381 
3382                         if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
3383                             setWifiState(WIFI_STATE_ENABLED);
3384                             // Load and re-enable networks when going back to enabled state
3385                             // This is essential for networks to show up after restore
3386                             mWifiConfigStore.loadAndEnableAllNetworks();
3387                             mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
3388                         } else {
3389                             mWifiConfigStore.enableAllNetworks();
3390                         }
3391 
3392                         mWifiNative.reconnect();
3393 
3394                         mOperationalMode = CONNECT_MODE;
3395                         transitionTo(mDisconnectedState);
3396                     } else {
3397                         // Nothing to do
3398                         return HANDLED;
3399                     }
3400                     break;
3401                 // Handle scan. All the connection related commands are
3402                 // handled only in ConnectModeState
3403                 case CMD_START_SCAN:
3404                     noteScanStart(message.arg1, (WorkSource) message.obj);
3405                     startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
3406                     break;
3407                 default:
3408                     return NOT_HANDLED;
3409             }
3410             return HANDLED;
3411         }
3412     }
3413 
3414     class ConnectModeState extends State {
3415         @Override
processMessage(Message message)3416         public boolean processMessage(Message message) {
3417             WifiConfiguration config;
3418             boolean ok;
3419             switch(message.what) {
3420                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3421                     mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
3422                     break;
3423                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3424                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
3425                     break;
3426                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3427                     SupplicantState state = handleSupplicantStateChange(message);
3428                     // A driver/firmware hang can now put the interface in a down state.
3429                     // We detect the interface going down and recover from it
3430                     if (!SupplicantState.isDriverActive(state)) {
3431                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
3432                             handleNetworkDisconnect();
3433                         }
3434                         log("Detected an interface down, restart driver");
3435                         transitionTo(mDriverStoppedState);
3436                         sendMessage(CMD_START_DRIVER);
3437                         break;
3438                     }
3439 
3440                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
3441                     // when authentication times out after a successful connection,
3442                     // we can figure this from the supplicant state. If supplicant
3443                     // state is DISCONNECTED, but the mNetworkInfo says we are not
3444                     // disconnected, we need to handle a disconnection
3445                     if (state == SupplicantState.DISCONNECTED &&
3446                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
3447                         if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
3448                         handleNetworkDisconnect();
3449                         transitionTo(mDisconnectedState);
3450                     }
3451                     break;
3452                 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
3453                     if (message.arg1 == 1) {
3454                         mWifiNative.disconnect();
3455                         mTemporarilyDisconnectWifi = true;
3456                     } else {
3457                         mWifiNative.reconnect();
3458                         mTemporarilyDisconnectWifi = false;
3459                     }
3460                     break;
3461                 case CMD_ADD_OR_UPDATE_NETWORK:
3462                     config = (WifiConfiguration) message.obj;
3463                     replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
3464                             mWifiConfigStore.addOrUpdateNetwork(config));
3465                     break;
3466                 case CMD_REMOVE_NETWORK:
3467                     ok = mWifiConfigStore.removeNetwork(message.arg1);
3468                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
3469                     break;
3470                 case CMD_ENABLE_NETWORK:
3471                     ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
3472                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
3473                     break;
3474                 case CMD_ENABLE_ALL_NETWORKS:
3475                     long time =  android.os.SystemClock.elapsedRealtime();
3476                     if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
3477                         mWifiConfigStore.enableAllNetworks();
3478                         mLastEnableAllNetworksTime = time;
3479                     }
3480                     break;
3481                 case WifiManager.DISABLE_NETWORK:
3482                     if (mWifiConfigStore.disableNetwork(message.arg1,
3483                             WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
3484                         replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
3485                     } else {
3486                         replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
3487                                 WifiManager.ERROR);
3488                     }
3489                     break;
3490                 case CMD_BLACKLIST_NETWORK:
3491                     mWifiNative.addToBlacklist((String)message.obj);
3492                     break;
3493                 case CMD_CLEAR_BLACKLIST:
3494                     mWifiNative.clearBlacklist();
3495                     break;
3496                 case CMD_SAVE_CONFIG:
3497                     ok = mWifiConfigStore.saveConfig();
3498                     replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
3499 
3500                     // Inform the backup manager about a data change
3501                     IBackupManager ibm = IBackupManager.Stub.asInterface(
3502                             ServiceManager.getService(Context.BACKUP_SERVICE));
3503                     if (ibm != null) {
3504                         try {
3505                             ibm.dataChanged("com.android.providers.settings");
3506                         } catch (Exception e) {
3507                             // Try again later
3508                         }
3509                     }
3510                     break;
3511                 case CMD_GET_CONFIGURED_NETWORKS:
3512                     replyToMessage(message, message.what,
3513                             mWifiConfigStore.getConfiguredNetworks());
3514                     break;
3515                     /* Do a redundant disconnect without transition */
3516                 case CMD_DISCONNECT:
3517                     mWifiNative.disconnect();
3518                     break;
3519                 case CMD_RECONNECT:
3520                     mWifiNative.reconnect();
3521                     break;
3522                 case CMD_REASSOCIATE:
3523                     mWifiNative.reassociate();
3524                     break;
3525                 case CMD_RELOAD_TLS_AND_RECONNECT:
3526                     if (mWifiConfigStore.needsUnlockedKeyStore()) {
3527                         logd("Reconnecting to give a chance to un-connected TLS networks");
3528                         mWifiNative.disconnect();
3529                         mWifiNative.reconnect();
3530                     }
3531                     break;
3532                 case WifiManager.CONNECT_NETWORK:
3533                     /* The connect message can contain a network id passed as arg1 on message or
3534                      * or a config passed as obj on message.
3535                      * For a new network, a config is passed to create and connect.
3536                      * For an existing network, a network id is passed
3537                      */
3538                     int netId = message.arg1;
3539                     config = (WifiConfiguration) message.obj;
3540 
3541                     /* Save the network config */
3542                     if (config != null) {
3543                         NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3544                         netId = result.getNetworkId();
3545                     }
3546 
3547                     if (mWifiConfigStore.selectNetwork(netId) &&
3548                             mWifiNative.reconnect()) {
3549                         /* The state tracker handles enabling networks upon completion/failure */
3550                         mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
3551                         replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
3552                         /* Expect a disconnection from the old connection */
3553                         transitionTo(mDisconnectingState);
3554                     } else {
3555                         loge("Failed to connect config: " + config + " netId: " + netId);
3556                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
3557                                 WifiManager.ERROR);
3558                         break;
3559                     }
3560                     break;
3561                 case WifiManager.SAVE_NETWORK:
3562                     config = (WifiConfiguration) message.obj;
3563                     NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3564                     if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
3565                         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
3566                     } else {
3567                         loge("Failed to save network");
3568                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3569                                 WifiManager.ERROR);
3570                     }
3571                     break;
3572                 case WifiManager.FORGET_NETWORK:
3573                     if (mWifiConfigStore.forgetNetwork(message.arg1)) {
3574                         replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
3575                     } else {
3576                         loge("Failed to forget network");
3577                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
3578                                 WifiManager.ERROR);
3579                     }
3580                     break;
3581                 case WifiManager.START_WPS:
3582                     WpsInfo wpsInfo = (WpsInfo) message.obj;
3583                     WpsResult wpsResult;
3584                     switch (wpsInfo.setup) {
3585                         case WpsInfo.PBC:
3586                             wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
3587                             break;
3588                         case WpsInfo.KEYPAD:
3589                             wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
3590                             break;
3591                         case WpsInfo.DISPLAY:
3592                             wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
3593                             break;
3594                         default:
3595                             wpsResult = new WpsResult(Status.FAILURE);
3596                             loge("Invalid setup for WPS");
3597                             break;
3598                     }
3599                     if (wpsResult.status == Status.SUCCESS) {
3600                         replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
3601                         transitionTo(mWpsRunningState);
3602                     } else {
3603                         loge("Failed to start WPS with config " + wpsInfo.toString());
3604                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
3605                     }
3606                     break;
3607                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3608                     if (DBG) log("Network connection established");
3609                     mLastNetworkId = message.arg1;
3610                     mLastBssid = (String) message.obj;
3611 
3612                     mWifiInfo.setBSSID(mLastBssid);
3613                     mWifiInfo.setNetworkId(mLastNetworkId);
3614                     /* send event to CM & network change broadcast */
3615                     setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
3616                     sendNetworkStateChangeBroadcast(mLastBssid);
3617                     transitionTo(mObtainingIpState);
3618                     break;
3619                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3620                     if (DBG) log("Network connection lost");
3621                     handleNetworkDisconnect();
3622                     transitionTo(mDisconnectedState);
3623                     break;
3624                 default:
3625                     return NOT_HANDLED;
3626             }
3627             return HANDLED;
3628         }
3629     }
3630 
3631     class L2ConnectedState extends State {
3632         @Override
enter()3633         public void enter() {
3634             mRssiPollToken++;
3635             if (mEnableRssiPolling) {
3636                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
3637             }
3638         }
3639 
3640         @Override
exit()3641         public void exit() {
3642             handleNetworkDisconnect();
3643         }
3644 
3645         @Override
processMessage(Message message)3646         public boolean processMessage(Message message) {
3647             switch (message.what) {
3648               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
3649                   handlePreDhcpSetup();
3650                   break;
3651               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
3652                   handlePostDhcpSetup();
3653                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
3654                       if (DBG) log("DHCP successful");
3655                       handleSuccessfulIpConfiguration((DhcpResults) message.obj);
3656                       transitionTo(mVerifyingLinkState);
3657                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
3658                       if (DBG) log("DHCP failed");
3659                       handleFailedIpConfiguration();
3660                       transitionTo(mDisconnectingState);
3661                   }
3662                   break;
3663                 case CMD_DISCONNECT:
3664                     mWifiNative.disconnect();
3665                     transitionTo(mDisconnectingState);
3666                     break;
3667                 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
3668                     if (message.arg1 == 1) {
3669                         mWifiNative.disconnect();
3670                         mTemporarilyDisconnectWifi = true;
3671                         transitionTo(mDisconnectingState);
3672                     }
3673                     break;
3674                 case CMD_SET_OPERATIONAL_MODE:
3675                     if (message.arg1 != CONNECT_MODE) {
3676                         sendMessage(CMD_DISCONNECT);
3677                         deferMessage(message);
3678                     }
3679                     break;
3680                 case CMD_SET_COUNTRY_CODE:
3681                     deferMessage(message);
3682                     break;
3683                 case CMD_START_SCAN:
3684                     /* Do not attempt to connect when we are already connected */
3685                     noteScanStart(message.arg1, (WorkSource) message.obj);
3686                     startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
3687                     break;
3688                     /* Ignore connection to same network */
3689                 case WifiManager.CONNECT_NETWORK:
3690                     int netId = message.arg1;
3691                     if (mWifiInfo.getNetworkId() == netId) {
3692                         break;
3693                     }
3694                     return NOT_HANDLED;
3695                 case WifiManager.SAVE_NETWORK:
3696                     WifiConfiguration config = (WifiConfiguration) message.obj;
3697                     NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3698                     if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
3699                         if (result.hasIpChanged()) {
3700                             log("Reconfiguring IP on connection");
3701                             transitionTo(mObtainingIpState);
3702                         }
3703                         if (result.hasProxyChanged()) {
3704                             log("Reconfiguring proxy on connection");
3705                             updateLinkProperties();
3706                         }
3707                     }
3708 
3709                     if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
3710                         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
3711                     } else {
3712                         loge("Failed to save network");
3713                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3714                                 WifiManager.ERROR);
3715                     }
3716                     break;
3717                     /* Ignore */
3718                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3719                     break;
3720                 case CMD_RSSI_POLL:
3721                     if (message.arg1 == mRssiPollToken) {
3722                         // Get Info and continue polling
3723                         fetchRssiAndLinkSpeedNative();
3724                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3725                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3726                     } else {
3727                         // Polling has completed
3728                     }
3729                     break;
3730                 case CMD_ENABLE_RSSI_POLL:
3731                     mEnableRssiPolling = (message.arg1 == 1);
3732                     mRssiPollToken++;
3733                     if (mEnableRssiPolling) {
3734                         // first poll
3735                         fetchRssiAndLinkSpeedNative();
3736                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3737                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3738                     }
3739                     break;
3740                 case WifiManager.RSSI_PKTCNT_FETCH:
3741                     RssiPacketCountInfo info = new RssiPacketCountInfo();
3742                     fetchRssiAndLinkSpeedNative();
3743                     info.rssi = mWifiInfo.getRssi();
3744                     fetchPktcntNative(info);
3745                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
3746                     break;
3747                 default:
3748                     return NOT_HANDLED;
3749             }
3750 
3751             return HANDLED;
3752         }
3753     }
3754 
3755     class ObtainingIpState extends State {
3756         @Override
enter()3757         public void enter() {
3758             if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
3759                 // TODO: If we're switching between static IP configuration and DHCP, remove the
3760                 // static configuration first.
3761                 startDhcp();
3762             } else {
3763                 // stop any running dhcp before assigning static IP
3764                 stopDhcp();
3765                 DhcpResults dhcpResults = new DhcpResults(
3766                         mWifiConfigStore.getLinkProperties(mLastNetworkId));
3767                 InterfaceConfiguration ifcg = new InterfaceConfiguration();
3768                 Iterator<LinkAddress> addrs =
3769                         dhcpResults.linkProperties.getLinkAddresses().iterator();
3770                 if (!addrs.hasNext()) {
3771                     loge("Static IP lacks address");
3772                     sendMessage(CMD_STATIC_IP_FAILURE);
3773                 } else {
3774                     ifcg.setLinkAddress(addrs.next());
3775                     ifcg.setInterfaceUp();
3776                     try {
3777                         mNwService.setInterfaceConfig(mInterfaceName, ifcg);
3778                         if (DBG) log("Static IP configuration succeeded");
3779                         sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
3780                     } catch (RemoteException re) {
3781                         loge("Static IP configuration failed: " + re);
3782                         sendMessage(CMD_STATIC_IP_FAILURE);
3783                     } catch (IllegalStateException e) {
3784                         loge("Static IP configuration failed: " + e);
3785                         sendMessage(CMD_STATIC_IP_FAILURE);
3786                     }
3787                 }
3788             }
3789         }
3790       @Override
processMessage(Message message)3791       public boolean processMessage(Message message) {
3792           if (DBG) log(getName() + message.toString() + "\n");
3793           switch(message.what) {
3794             case CMD_STATIC_IP_SUCCESS:
3795                   handleSuccessfulIpConfiguration((DhcpResults) message.obj);
3796                   transitionTo(mVerifyingLinkState);
3797                   break;
3798               case CMD_STATIC_IP_FAILURE:
3799                   handleFailedIpConfiguration();
3800                   transitionTo(mDisconnectingState);
3801                   break;
3802              case WifiManager.SAVE_NETWORK:
3803                   deferMessage(message);
3804                   break;
3805                   /* Defer any power mode changes since we must keep active power mode at DHCP */
3806               case CMD_SET_HIGH_PERF_MODE:
3807                   deferMessage(message);
3808                   break;
3809                   /* Defer scan request since we should not switch to other channels at DHCP */
3810               case CMD_START_SCAN:
3811                   deferMessage(message);
3812                   break;
3813               default:
3814                   return NOT_HANDLED;
3815           }
3816           return HANDLED;
3817       }
3818     }
3819 
3820     class VerifyingLinkState extends State {
3821         @Override
enter()3822         public void enter() {
3823             log(getName() + " enter");
3824             setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
3825             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
3826             sendNetworkStateChangeBroadcast(mLastBssid);
3827         }
3828         @Override
processMessage(Message message)3829         public boolean processMessage(Message message) {
3830             switch (message.what) {
3831                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3832                     //stay here
3833                     log(getName() + " POOR_LINK_DETECTED: no transition");
3834                     break;
3835                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
3836                     log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check");
3837                     transitionTo(mCaptivePortalCheckState);
3838                     break;
3839                 default:
3840                     if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED");
3841                     return NOT_HANDLED;
3842             }
3843             return HANDLED;
3844         }
3845     }
3846 
3847     class CaptivePortalCheckState extends State {
3848         @Override
enter()3849         public void enter() {
3850             log(getName() + " enter");
3851             setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK);
3852             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK);
3853             sendNetworkStateChangeBroadcast(mLastBssid);
3854         }
3855         @Override
processMessage(Message message)3856         public boolean processMessage(Message message) {
3857             switch (message.what) {
3858                 case CMD_CAPTIVE_CHECK_COMPLETE:
3859                     log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE");
3860                     try {
3861                         mNwService.enableIpv6(mInterfaceName);
3862                     } catch (RemoteException re) {
3863                         loge("Failed to enable IPv6: " + re);
3864                     } catch (IllegalStateException e) {
3865                         loge("Failed to enable IPv6: " + e);
3866                     }
3867                     setNetworkDetailedState(DetailedState.CONNECTED);
3868                     mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
3869                     sendNetworkStateChangeBroadcast(mLastBssid);
3870                     transitionTo(mConnectedState);
3871                     break;
3872                 default:
3873                     return NOT_HANDLED;
3874             }
3875             return HANDLED;
3876         }
3877     }
3878 
3879     class ConnectedState extends State {
3880         @Override
processMessage(Message message)3881         public boolean processMessage(Message message) {
3882             switch (message.what) {
3883                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3884                     if (DBG) log("Watchdog reports poor link");
3885                     try {
3886                         mNwService.disableIpv6(mInterfaceName);
3887                     } catch (RemoteException re) {
3888                         loge("Failed to disable IPv6: " + re);
3889                     } catch (IllegalStateException e) {
3890                         loge("Failed to disable IPv6: " + e);
3891                     }
3892                     /* Report a disconnect */
3893                     setNetworkDetailedState(DetailedState.DISCONNECTED);
3894                     mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
3895                     sendNetworkStateChangeBroadcast(mLastBssid);
3896 
3897                     transitionTo(mVerifyingLinkState);
3898                     break;
3899                 default:
3900                     return NOT_HANDLED;
3901             }
3902             return HANDLED;
3903         }
3904         @Override
exit()3905         public void exit() {
3906             /* Request a CS wakelock during transition to mobile */
3907             checkAndSetConnectivityInstance();
3908             mCm.requestNetworkTransitionWakelock(getName());
3909         }
3910     }
3911 
3912     class DisconnectingState extends State {
3913         @Override
processMessage(Message message)3914         public boolean processMessage(Message message) {
3915             switch (message.what) {
3916                 case CMD_SET_OPERATIONAL_MODE:
3917                     if (message.arg1 != CONNECT_MODE) {
3918                         deferMessage(message);
3919                     }
3920                     break;
3921                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3922                     /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
3923                      * we have missed the network disconnection, transition to mDisconnectedState
3924                      * and handle the rest of the events there
3925                      */
3926                     deferMessage(message);
3927                     handleNetworkDisconnect();
3928                     transitionTo(mDisconnectedState);
3929                     break;
3930                 default:
3931                     return NOT_HANDLED;
3932             }
3933             return HANDLED;
3934         }
3935     }
3936 
3937     class DisconnectedState extends State {
3938         private boolean mAlarmEnabled = false;
3939         /* This is set from the overlay config file or from a secure setting.
3940          * A value of 0 disables scanning in the framework.
3941          */
3942         private long mFrameworkScanIntervalMs;
3943 
setScanAlarm(boolean enabled)3944         private void setScanAlarm(boolean enabled) {
3945             if (enabled == mAlarmEnabled) return;
3946             if (enabled) {
3947                 if (mFrameworkScanIntervalMs > 0) {
3948                     mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
3949                             System.currentTimeMillis() + mFrameworkScanIntervalMs,
3950                             mFrameworkScanIntervalMs,
3951                             mScanIntent);
3952                     mAlarmEnabled = true;
3953                 }
3954             } else {
3955                 mAlarmManager.cancel(mScanIntent);
3956                 mAlarmEnabled = false;
3957             }
3958         }
3959 
3960         @Override
enter()3961         public void enter() {
3962             // We dont scan frequently if this is a temporary disconnect
3963             // due to p2p
3964             if (mTemporarilyDisconnectWifi) {
3965                 mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE);
3966                 return;
3967             }
3968 
3969             mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
3970                     Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
3971                     mDefaultFrameworkScanIntervalMs);
3972             /*
3973              * We initiate background scanning if it is enabled, otherwise we
3974              * initiate an infrequent scan that wakes up the device to ensure
3975              * a user connects to an access point on the move
3976              */
3977             if (mEnableBackgroundScan) {
3978                 /* If a regular scan result is pending, do not initiate background
3979                  * scan until the scan results are returned. This is needed because
3980                  * initiating a background scan will cancel the regular scan and
3981                  * scan results will not be returned until background scanning is
3982                  * cleared
3983                  */
3984                 if (!mScanResultIsPending) {
3985                     mWifiNative.enableBackgroundScan(true);
3986                 }
3987             } else {
3988                 setScanAlarm(true);
3989             }
3990 
3991             /**
3992              * If we have no networks saved, the supplicant stops doing the periodic scan.
3993              * The scans are useful to notify the user of the presence of an open network.
3994              * Note that these are not wake up scans.
3995              */
3996             if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3997                 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3998                             ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3999             }
4000         }
4001         @Override
processMessage(Message message)4002         public boolean processMessage(Message message) {
4003             boolean ret = HANDLED;
4004             switch (message.what) {
4005                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
4006                     if (mP2pConnected.get()) break;
4007                     if (message.arg1 == mPeriodicScanToken &&
4008                             mWifiConfigStore.getConfiguredNetworks().size() == 0) {
4009                         sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE, 0, (WorkSource) null);
4010                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
4011                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
4012                     }
4013                     break;
4014                 case WifiManager.FORGET_NETWORK:
4015                 case CMD_REMOVE_NETWORK:
4016                     // Set up a delayed message here. After the forget/remove is handled
4017                     // the handled delayed message will determine if there is a need to
4018                     // scan and continue
4019                     sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
4020                                 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
4021                     ret = NOT_HANDLED;
4022                     break;
4023                 case CMD_SET_OPERATIONAL_MODE:
4024                     if (message.arg1 != CONNECT_MODE) {
4025                         mOperationalMode = message.arg1;
4026 
4027                         mWifiConfigStore.disableAllNetworks();
4028                         if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
4029                             mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
4030                             setWifiState(WIFI_STATE_DISABLED);
4031                         }
4032 
4033                         transitionTo(mScanModeState);
4034                     }
4035                     break;
4036                 case CMD_ENABLE_BACKGROUND_SCAN:
4037                     mEnableBackgroundScan = (message.arg1 == 1);
4038                     if (mEnableBackgroundScan) {
4039                         mWifiNative.enableBackgroundScan(true);
4040                         setScanAlarm(false);
4041                     } else {
4042                         mWifiNative.enableBackgroundScan(false);
4043                         setScanAlarm(true);
4044                     }
4045                     break;
4046                     /* Ignore network disconnect */
4047                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4048                     break;
4049                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4050                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
4051                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
4052                     /* ConnectModeState does the rest of the handling */
4053                     ret = NOT_HANDLED;
4054                     break;
4055                 case CMD_START_SCAN:
4056                     /* Disable background scan temporarily during a regular scan */
4057                     if (mEnableBackgroundScan) {
4058                         mWifiNative.enableBackgroundScan(false);
4059                     }
4060                     /* Handled in parent state */
4061                     ret = NOT_HANDLED;
4062                     break;
4063                 case WifiMonitor.SCAN_RESULTS_EVENT:
4064                     /* Re-enable background scan when a pending scan result is received */
4065                     if (mEnableBackgroundScan && mScanResultIsPending) {
4066                         mWifiNative.enableBackgroundScan(true);
4067                     }
4068                     /* Handled in parent state */
4069                     ret = NOT_HANDLED;
4070                     break;
4071                 case WifiP2pService.P2P_CONNECTION_CHANGED:
4072                     NetworkInfo info = (NetworkInfo) message.obj;
4073                     mP2pConnected.set(info.isConnected());
4074                     if (mP2pConnected.get()) {
4075                         int defaultInterval = mContext.getResources().getInteger(
4076                                 R.integer.config_wifi_scan_interval_p2p_connected);
4077                         long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
4078                                 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
4079                                 defaultInterval);
4080                         mWifiNative.setScanInterval((int) scanIntervalMs/1000);
4081                     } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
4082                         if (DBG) log("Turn on scanning after p2p disconnected");
4083                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
4084                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
4085                     }
4086                 case CMD_RECONNECT:
4087                 case CMD_REASSOCIATE:
4088                     if (mTemporarilyDisconnectWifi) {
4089                         // Drop a third party reconnect/reassociate if STA is
4090                         // temporarily disconnected for p2p
4091                         break;
4092                     } else {
4093                         // ConnectModeState handles it
4094                         ret = NOT_HANDLED;
4095                     }
4096                     break;
4097                 default:
4098                     ret = NOT_HANDLED;
4099             }
4100             return ret;
4101         }
4102 
4103         @Override
exit()4104         public void exit() {
4105             /* No need for a background scan upon exit from a disconnected state */
4106             if (mEnableBackgroundScan) {
4107                 mWifiNative.enableBackgroundScan(false);
4108             }
4109             setScanAlarm(false);
4110         }
4111     }
4112 
4113     class WpsRunningState extends State {
4114         //Tracks the source to provide a reply
4115         private Message mSourceMessage;
4116         @Override
enter()4117         public void enter() {
4118             mSourceMessage = Message.obtain(getCurrentMessage());
4119         }
4120         @Override
processMessage(Message message)4121         public boolean processMessage(Message message) {
4122             switch (message.what) {
4123                 case WifiMonitor.WPS_SUCCESS_EVENT:
4124                     // Ignore intermediate success, wait for full connection
4125                     break;
4126                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
4127                     replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
4128                     mSourceMessage.recycle();
4129                     mSourceMessage = null;
4130                     deferMessage(message);
4131                     transitionTo(mDisconnectedState);
4132                     break;
4133                 case WifiMonitor.WPS_OVERLAP_EVENT:
4134                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
4135                             WifiManager.WPS_OVERLAP_ERROR);
4136                     mSourceMessage.recycle();
4137                     mSourceMessage = null;
4138                     transitionTo(mDisconnectedState);
4139                     break;
4140                 case WifiMonitor.WPS_FAIL_EVENT:
4141                     //arg1 has the reason for the failure
4142                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
4143                     mSourceMessage.recycle();
4144                     mSourceMessage = null;
4145                     transitionTo(mDisconnectedState);
4146                     break;
4147                 case WifiMonitor.WPS_TIMEOUT_EVENT:
4148                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
4149                             WifiManager.WPS_TIMED_OUT);
4150                     mSourceMessage.recycle();
4151                     mSourceMessage = null;
4152                     transitionTo(mDisconnectedState);
4153                     break;
4154                 case WifiManager.START_WPS:
4155                     replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
4156                     break;
4157                 case WifiManager.CANCEL_WPS:
4158                     if (mWifiNative.cancelWps()) {
4159                         replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
4160                     } else {
4161                         replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
4162                     }
4163                     transitionTo(mDisconnectedState);
4164                     break;
4165                 /* Defer all commands that can cause connections to a different network
4166                  * or put the state machine out of connect mode
4167                  */
4168                 case CMD_STOP_DRIVER:
4169                 case CMD_SET_OPERATIONAL_MODE:
4170                 case WifiManager.CONNECT_NETWORK:
4171                 case CMD_ENABLE_NETWORK:
4172                 case CMD_RECONNECT:
4173                 case CMD_REASSOCIATE:
4174                     deferMessage(message);
4175                     break;
4176                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
4177                     if (DBG) log("Network connection lost");
4178                     handleNetworkDisconnect();
4179                     break;
4180                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
4181                     if (DBG) log("Ignore Assoc reject event during WPS Connection");
4182                     break;
4183                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
4184                     // Disregard auth failure events during WPS connection. The
4185                     // EAP sequence is retried several times, and there might be
4186                     // failures (especially for wps pin). We will get a WPS_XXX
4187                     // event at the end of the sequence anyway.
4188                     if (DBG) log("Ignore auth failure during WPS connection");
4189                     break;
4190                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
4191                     //Throw away supplicant state changes when WPS is running.
4192                     //We will start getting supplicant state changes once we get
4193                     //a WPS success or failure
4194                     break;
4195                 default:
4196                     return NOT_HANDLED;
4197             }
4198             return HANDLED;
4199         }
4200 
4201         @Override
exit()4202         public void exit() {
4203             mWifiConfigStore.enableAllNetworks();
4204             mWifiConfigStore.loadConfiguredNetworks();
4205         }
4206     }
4207 
4208     class SoftApStartingState extends State {
4209         @Override
enter()4210         public void enter() {
4211             final Message message = getCurrentMessage();
4212             if (message.what == CMD_START_AP) {
4213                 final WifiConfiguration config = (WifiConfiguration) message.obj;
4214 
4215                 if (config == null) {
4216                     mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
4217                 } else {
4218                     mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
4219                     startSoftApWithConfig(config);
4220                 }
4221             } else {
4222                 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
4223             }
4224         }
4225         @Override
processMessage(Message message)4226         public boolean processMessage(Message message) {
4227             switch(message.what) {
4228                 case CMD_START_SUPPLICANT:
4229                 case CMD_STOP_SUPPLICANT:
4230                 case CMD_START_AP:
4231                 case CMD_STOP_AP:
4232                 case CMD_START_DRIVER:
4233                 case CMD_STOP_DRIVER:
4234                 case CMD_SET_OPERATIONAL_MODE:
4235                 case CMD_SET_COUNTRY_CODE:
4236                 case CMD_SET_FREQUENCY_BAND:
4237                 case CMD_START_PACKET_FILTERING:
4238                 case CMD_STOP_PACKET_FILTERING:
4239                 case CMD_TETHER_STATE_CHANGE:
4240                     deferMessage(message);
4241                     break;
4242                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
4243                     WifiConfiguration config = (WifiConfiguration) message.obj;
4244                     if (config != null) {
4245                         startSoftApWithConfig(config);
4246                     } else {
4247                         loge("Softap config is null!");
4248                         sendMessage(CMD_START_AP_FAILURE);
4249                     }
4250                     break;
4251                 case CMD_START_AP_SUCCESS:
4252                     setWifiApState(WIFI_AP_STATE_ENABLED);
4253                     transitionTo(mSoftApStartedState);
4254                     break;
4255                 case CMD_START_AP_FAILURE:
4256                     setWifiApState(WIFI_AP_STATE_FAILED);
4257                     transitionTo(mInitialState);
4258                     break;
4259                 default:
4260                     return NOT_HANDLED;
4261             }
4262             return HANDLED;
4263         }
4264     }
4265 
4266     class SoftApStartedState extends State {
4267         @Override
processMessage(Message message)4268         public boolean processMessage(Message message) {
4269             switch(message.what) {
4270                 case CMD_STOP_AP:
4271                     if (DBG) log("Stopping Soft AP");
4272                     /* We have not tethered at this point, so we just shutdown soft Ap */
4273                     try {
4274                         mNwService.stopAccessPoint(mInterfaceName);
4275                     } catch(Exception e) {
4276                         loge("Exception in stopAccessPoint()");
4277                     }
4278                     setWifiApState(WIFI_AP_STATE_DISABLED);
4279                     transitionTo(mInitialState);
4280                     break;
4281                 case CMD_START_AP:
4282                     // Ignore a start on a running access point
4283                     break;
4284                     /* Fail client mode operation when soft AP is enabled */
4285                 case CMD_START_SUPPLICANT:
4286                     loge("Cannot start supplicant with a running soft AP");
4287                     setWifiState(WIFI_STATE_UNKNOWN);
4288                     break;
4289                 case CMD_TETHER_STATE_CHANGE:
4290                     TetherStateChange stateChange = (TetherStateChange) message.obj;
4291                     if (startTethering(stateChange.available)) {
4292                         transitionTo(mTetheringState);
4293                     }
4294                     break;
4295                 default:
4296                     return NOT_HANDLED;
4297             }
4298             return HANDLED;
4299         }
4300     }
4301 
4302     class TetheringState extends State {
4303         @Override
enter()4304         public void enter() {
4305             /* Send ourselves a delayed message to shut down if tethering fails to notify */
4306             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
4307                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
4308         }
4309         @Override
processMessage(Message message)4310         public boolean processMessage(Message message) {
4311             switch(message.what) {
4312                 case CMD_TETHER_STATE_CHANGE:
4313                     TetherStateChange stateChange = (TetherStateChange) message.obj;
4314                     if (isWifiTethered(stateChange.active)) {
4315                         transitionTo(mTetheredState);
4316                     }
4317                     return HANDLED;
4318                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
4319                     if (message.arg1 == mTetherToken) {
4320                         loge("Failed to get tether update, shutdown soft access point");
4321                         transitionTo(mSoftApStartedState);
4322                         // Needs to be first thing handled
4323                         sendMessageAtFrontOfQueue(CMD_STOP_AP);
4324                     }
4325                     break;
4326                 case CMD_START_SUPPLICANT:
4327                 case CMD_STOP_SUPPLICANT:
4328                 case CMD_START_AP:
4329                 case CMD_STOP_AP:
4330                 case CMD_START_DRIVER:
4331                 case CMD_STOP_DRIVER:
4332                 case CMD_SET_OPERATIONAL_MODE:
4333                 case CMD_SET_COUNTRY_CODE:
4334                 case CMD_SET_FREQUENCY_BAND:
4335                 case CMD_START_PACKET_FILTERING:
4336                 case CMD_STOP_PACKET_FILTERING:
4337                     deferMessage(message);
4338                     break;
4339                 default:
4340                     return NOT_HANDLED;
4341             }
4342             return HANDLED;
4343         }
4344     }
4345 
4346     class TetheredState extends State {
4347         @Override
processMessage(Message message)4348         public boolean processMessage(Message message) {
4349             switch(message.what) {
4350                 case CMD_TETHER_STATE_CHANGE:
4351                     TetherStateChange stateChange = (TetherStateChange) message.obj;
4352                     if (!isWifiTethered(stateChange.active)) {
4353                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
4354                         setHostApRunning(null, false);
4355                         setHostApRunning(null, true);
4356                     }
4357                     return HANDLED;
4358                 case CMD_STOP_AP:
4359                     if (DBG) log("Untethering before stopping AP");
4360                     setWifiApState(WIFI_AP_STATE_DISABLING);
4361                     stopTethering();
4362                     transitionTo(mUntetheringState);
4363                     // More work to do after untethering
4364                     deferMessage(message);
4365                     break;
4366                 default:
4367                     return NOT_HANDLED;
4368             }
4369             return HANDLED;
4370         }
4371     }
4372 
4373     class UntetheringState extends State {
4374         @Override
enter()4375         public void enter() {
4376             /* Send ourselves a delayed message to shut down if tethering fails to notify */
4377             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
4378                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
4379 
4380         }
4381         @Override
processMessage(Message message)4382         public boolean processMessage(Message message) {
4383             switch(message.what) {
4384                 case CMD_TETHER_STATE_CHANGE:
4385                     TetherStateChange stateChange = (TetherStateChange) message.obj;
4386 
4387                     /* Wait till wifi is untethered */
4388                     if (isWifiTethered(stateChange.active)) break;
4389 
4390                     transitionTo(mSoftApStartedState);
4391                     break;
4392                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
4393                     if (message.arg1 == mTetherToken) {
4394                         loge("Failed to get tether update, force stop access point");
4395                         transitionTo(mSoftApStartedState);
4396                     }
4397                     break;
4398                 case CMD_START_SUPPLICANT:
4399                 case CMD_STOP_SUPPLICANT:
4400                 case CMD_START_AP:
4401                 case CMD_STOP_AP:
4402                 case CMD_START_DRIVER:
4403                 case CMD_STOP_DRIVER:
4404                 case CMD_SET_OPERATIONAL_MODE:
4405                 case CMD_SET_COUNTRY_CODE:
4406                 case CMD_SET_FREQUENCY_BAND:
4407                 case CMD_START_PACKET_FILTERING:
4408                 case CMD_STOP_PACKET_FILTERING:
4409                     deferMessage(message);
4410                     break;
4411                 default:
4412                     return NOT_HANDLED;
4413             }
4414             return HANDLED;
4415         }
4416     }
4417 
4418     //State machine initiated requests can have replyTo set to null indicating
4419     //there are no recepients, we ignore those reply actions
replyToMessage(Message msg, int what)4420     private void replyToMessage(Message msg, int what) {
4421         if (msg.replyTo == null) return;
4422         Message dstMsg = obtainMessageWithArg2(msg);
4423         dstMsg.what = what;
4424         mReplyChannel.replyToMessage(msg, dstMsg);
4425     }
4426 
replyToMessage(Message msg, int what, int arg1)4427     private void replyToMessage(Message msg, int what, int arg1) {
4428         if (msg.replyTo == null) return;
4429         Message dstMsg = obtainMessageWithArg2(msg);
4430         dstMsg.what = what;
4431         dstMsg.arg1 = arg1;
4432         mReplyChannel.replyToMessage(msg, dstMsg);
4433     }
4434 
replyToMessage(Message msg, int what, Object obj)4435     private void replyToMessage(Message msg, int what, Object obj) {
4436         if (msg.replyTo == null) return;
4437         Message dstMsg = obtainMessageWithArg2(msg);
4438         dstMsg.what = what;
4439         dstMsg.obj = obj;
4440         mReplyChannel.replyToMessage(msg, dstMsg);
4441     }
4442 
4443     /**
4444      * arg2 on the source message has a unique id that needs to be retained in replies
4445      * to match the request
4446 
4447      * see WifiManager for details
4448      */
obtainMessageWithArg2(Message srcMsg)4449     private Message obtainMessageWithArg2(Message srcMsg) {
4450         Message msg = Message.obtain();
4451         msg.arg2 = srcMsg.arg2;
4452         return msg;
4453     }
4454 }
4455