WifiStateMachine.java revision 095c58b73ac112cc7e00771430765434893d8bc5
13fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka/*
23fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project
33fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
43fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
53fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * you may not use this file except in compliance with the License.
63fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * You may obtain a copy of the License at
73fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
83fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
93fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
103fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
113fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
123fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * See the License for the specific language governing permissions and
143fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * limitations under the License.
153fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka */
163fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
173fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokapackage android.net.wifi;
183fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
193fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
203fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
213fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
223fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
233fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
243fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
253fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka/**
263fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * TODO: Add soft AP states as part of WIFI_STATE_XXX
273fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Retain WIFI_STATE_ENABLING that indicates driver is loading
283fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
293fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * and WIFI_STATE_FAILED for failure
303fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Deprecate WIFI_STATE_UNKNOWN
313fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
323fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Doing this will simplify the logic for sending broadcasts
333fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka */
343fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
353fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
363fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
373fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
383fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
393fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
403fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.app.AlarmManager;
413fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.app.PendingIntent;
423fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.app.backup.IBackupManager;
433fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.bluetooth.BluetoothAdapter;
443fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.content.BroadcastReceiver;
453fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.content.Context;
463fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.content.Intent;
473fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.content.IntentFilter;
483fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.content.pm.PackageManager;
493fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.ConnectivityManager;
503fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.DhcpInfo;
513fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.DhcpInfoInternal;
523fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.DhcpStateMachine;
533fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.InterfaceConfiguration;
543fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.LinkAddress;
553fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.LinkProperties;
563fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.NetworkInfo;
573fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.NetworkInfo.DetailedState;
583fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.NetworkUtils;
593fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.wifi.WpsResult.Status;
603fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.wifi.p2p.WifiP2pManager;
613fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.wifi.p2p.WifiP2pService;
623fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.net.wifi.StateChangeResult;
633fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.Binder;
643fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.IBinder;
653fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.INetworkManagementService;
663fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.Message;
673fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.Messenger;
683fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.PowerManager;
693fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.Process;
703fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.RemoteException;
713fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.ServiceManager;
723fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.SystemClock;
733fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.SystemProperties;
743fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.os.WorkSource;
753fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.provider.Settings;
763fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.util.EventLog;
773fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.util.Log;
783fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport android.util.LruCache;
793fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
803fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport com.android.internal.app.IBatteryStats;
813fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport com.android.internal.util.AsyncChannel;
823fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport com.android.internal.util.Protocol;
833fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport com.android.internal.util.State;
843fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport com.android.internal.util.StateMachine;
853fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
863fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.net.InetAddress;
873fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.util.ArrayList;
883fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.util.List;
893fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.util.concurrent.atomic.AtomicInteger;
903fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.util.concurrent.atomic.AtomicBoolean;
913fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokaimport java.util.regex.Pattern;
923fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
933fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka/**
943fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Track the state of Wifi connectivity. All event handling is done here,
953fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * and all changes in connectivity state are initiated here.
963fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
973fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * Wi-Fi now supports three modes of operation: Client, Soft Ap and Direct
983fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * In the current implementation, we do not support any concurrency and thus only
993fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * one of Client, Soft Ap or Direct operation is supported at any time.
1003fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
1013fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * The WifiStateMachine supports Soft Ap and Client operations while WifiP2pService
1023fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * handles Direct. WifiP2pService and WifiStateMachine co-ordinate to ensure only
1033fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * one exists at a certain time.
1043fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka *
1053fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka * @hide
1063fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka */
1073fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaokapublic class WifiStateMachine extends StateMachine {
1083db07d05a366c003fd57a1a1eeb78e81c3a747ccTadashi G. Takaoka
1093db07d05a366c003fd57a1a1eeb78e81c3a747ccTadashi G. Takaoka    private static final String TAG = "WifiStateMachine";
1103fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private static final String NETWORKTYPE = "WIFI";
1113fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private static final boolean DBG = false;
1123fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
1133fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    /* TODO: This is no more used with the hostapd code. Clean up */
1143fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private static final String SOFTAP_IFACE = "wl0.1";
1153fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka
1163fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private WifiMonitor mWifiMonitor;
1173fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private WifiNative mWifiNative;
1183fbf9f85a296f33a13272547013677942cd9d12fTadashi G. Takaoka    private WifiConfigStore mWifiConfigStore;
119    private INetworkManagementService mNwService;
120    private ConnectivityManager mCm;
121
122    private final boolean mP2pSupported;
123    private final String mPrimaryDeviceType;
124
125    /* Scan results handling */
126    private List<ScanResult> mScanResults;
127    private static final Pattern scanResultPattern = Pattern.compile("\t+");
128    private static final int SCAN_RESULT_CACHE_SIZE = 80;
129    private final LruCache<String, ScanResult> mScanResultCache;
130
131    /* Chipset supports background scan */
132    private final boolean mBackgroundScanSupported;
133
134    private String mInterfaceName;
135    /* Tethering interface could be seperate from wlan interface */
136    private String mTetherInterfaceName;
137
138    private int mLastSignalLevel = -1;
139    private String mLastBssid;
140    private int mLastNetworkId;
141    private boolean mEnableRssiPolling = false;
142    private boolean mEnableBackgroundScan = false;
143    private int mRssiPollToken = 0;
144    private int mReconnectCount = 0;
145    private boolean mIsScanMode = false;
146    private boolean mScanResultIsPending = false;
147    /* Tracks if the current scan settings are active */
148    private boolean mSetScanActive = false;
149    /* High perf mode is true if an app has held a high perf Wifi Lock */
150    private boolean mHighPerfMode = false;
151
152    private boolean mBluetoothConnectionActive = false;
153
154    private BroadcastReceiver mScreenReceiver;
155    private IntentFilter mScreenFilter;
156    private PowerManager.WakeLock mSuspendWakeLock;
157
158    /**
159     * Interval in milliseconds between polling for RSSI
160     * and linkspeed information
161     */
162    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
163
164    /**
165     * Delay between supplicant restarts upon failure to establish connection
166     */
167    private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
168
169    /**
170     * Number of times we attempt to restart supplicant
171     */
172    private static final int SUPPLICANT_RESTART_TRIES = 5;
173
174    private int mSupplicantRestartCount = 0;
175    /* Tracks sequence number on stop failure message */
176    private int mSupplicantStopFailureToken = 0;
177
178    /**
179     * Tether state change notification time out
180     */
181    private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
182
183    /* Tracks sequence number on a tether notification time out */
184    private int mTetherToken = 0;
185
186    /**
187     * Driver start time out.
188     */
189    private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
190
191    /* Tracks sequence number on a driver time out */
192    private int mDriverStartToken = 0;
193
194    private LinkProperties mLinkProperties;
195
196    /* Tracks sequence number on a periodic scan message */
197    private int mPeriodicScanToken = 0;
198
199    // Wakelock held during wifi start/stop and driver load/unload
200    private PowerManager.WakeLock mWakeLock;
201
202    private Context mContext;
203
204    private DhcpInfoInternal mDhcpInfoInternal;
205    private WifiInfo mWifiInfo;
206    private NetworkInfo mNetworkInfo;
207    private SupplicantStateTracker mSupplicantStateTracker;
208    private DhcpStateMachine mDhcpStateMachine;
209
210    private AlarmManager mAlarmManager;
211    private PendingIntent mScanIntent;
212    private PendingIntent mDriverStopIntent;
213
214    /* Tracks current frequency mode */
215    private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
216
217    /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
218    private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
219
220    // Channel for sending replies.
221    private AsyncChannel mReplyChannel = new AsyncChannel();
222
223    private WifiP2pManager mWifiP2pManager;
224    //Used to initiate a connection with WifiP2pService
225    private AsyncChannel mWifiP2pChannel = new AsyncChannel();
226    private AsyncChannel mWifiApConfigChannel = new AsyncChannel();
227
228    // Event log tags (must be in sync with event-log-tags)
229    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
230    private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
231    private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
232
233    /* The base for wifi message types */
234    static final int BASE = Protocol.BASE_WIFI;
235    /* Load the driver */
236    static final int CMD_LOAD_DRIVER                      = BASE + 1;
237    /* Unload the driver */
238    static final int CMD_UNLOAD_DRIVER                    = BASE + 2;
239    /* Indicates driver load succeeded */
240    static final int CMD_LOAD_DRIVER_SUCCESS              = BASE + 3;
241    /* Indicates driver load failed */
242    static final int CMD_LOAD_DRIVER_FAILURE              = BASE + 4;
243    /* Indicates driver unload succeeded */
244    static final int CMD_UNLOAD_DRIVER_SUCCESS            = BASE + 5;
245    /* Indicates driver unload failed */
246    static final int CMD_UNLOAD_DRIVER_FAILURE            = BASE + 6;
247
248    /* Start the supplicant */
249    static final int CMD_START_SUPPLICANT                 = BASE + 11;
250    /* Stop the supplicant */
251    static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
252    /* Start the driver */
253    static final int CMD_START_DRIVER                     = BASE + 13;
254    /* Stop the driver */
255    static final int CMD_STOP_DRIVER                      = BASE + 14;
256    /* Indicates Static IP succeded */
257    static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
258    /* Indicates Static IP failed */
259    static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
260    /* Indicates supplicant stop failed */
261    static final int CMD_STOP_SUPPLICANT_FAILED           = BASE + 17;
262    /* Delayed stop to avoid shutting down driver too quick*/
263    static final int CMD_DELAYED_STOP_DRIVER              = BASE + 18;
264    /* A delayed message sent to start driver when it fail to come up */
265    static final int CMD_DRIVER_START_TIMED_OUT           = BASE + 19;
266
267    /* Start the soft access point */
268    static final int CMD_START_AP                         = BASE + 21;
269    /* Indicates soft ap start succeded */
270    static final int CMD_START_AP_SUCCESS                 = BASE + 22;
271    /* Indicates soft ap start failed */
272    static final int CMD_START_AP_FAILURE                 = BASE + 23;
273    /* Stop the soft access point */
274    static final int CMD_STOP_AP                          = BASE + 24;
275    /* Set the soft access point configuration */
276    static final int CMD_SET_AP_CONFIG                    = BASE + 25;
277    /* Soft access point configuration set completed */
278    static final int CMD_SET_AP_CONFIG_COMPLETED          = BASE + 26;
279    /* Request the soft access point configuration */
280    static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
281    /* Response to access point configuration request */
282    static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
283    /* Invoked when getting a tether state change notification */
284    static final int CMD_TETHER_STATE_CHANGE              = BASE + 29;
285    /* A delayed message sent to indicate tether state change failed to arrive */
286    static final int CMD_TETHER_NOTIFICATION_TIMED_OUT    = BASE + 30;
287
288    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 31;
289
290    /* Supplicant commands */
291    /* Is supplicant alive ? */
292    static final int CMD_PING_SUPPLICANT                  = BASE + 51;
293    /* Add/update a network configuration */
294    static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
295    /* Delete a network */
296    static final int CMD_REMOVE_NETWORK                   = BASE + 53;
297    /* Enable a network. The device will attempt a connection to the given network. */
298    static final int CMD_ENABLE_NETWORK                   = BASE + 54;
299    /* Enable all networks */
300    static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
301    /* Blacklist network. De-prioritizes the given BSSID for connection. */
302    static final int CMD_BLACKLIST_NETWORK                = BASE + 56;
303    /* Clear the blacklist network list */
304    static final int CMD_CLEAR_BLACKLIST                  = BASE + 57;
305    /* Save configuration */
306    static final int CMD_SAVE_CONFIG                      = BASE + 58;
307    /* Get configured networks*/
308    static final int CMD_GET_CONFIGURED_NETWORKS          = BASE + 59;
309
310    /* Supplicant commands after driver start*/
311    /* Initiate a scan */
312    static final int CMD_START_SCAN                       = BASE + 71;
313    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
314    static final int CMD_SET_SCAN_MODE                    = BASE + 72;
315    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
316    static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
317    /* Disconnect from a network */
318    static final int CMD_DISCONNECT                       = BASE + 74;
319    /* Reconnect to a network */
320    static final int CMD_RECONNECT                        = BASE + 75;
321    /* Reassociate to a network */
322    static final int CMD_REASSOCIATE                      = BASE + 76;
323    /* Controls suspend mode optimizations
324     *
325     * When high perf mode is enabled, suspend mode optimizations are disabled
326     *
327     * When high perf mode is disabled, suspend mode optimizations are enabled
328     *
329     * Suspend mode optimizations include:
330     * - packet filtering
331     * - turn off roaming
332     * - DTIM wake up settings
333     */
334    static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
335    /* Set the country code */
336    static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
337    /* Enables RSSI poll */
338    static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
339    /* RSSI poll */
340    static final int CMD_RSSI_POLL                        = BASE + 83;
341    /* Set up packet filtering */
342    static final int CMD_START_PACKET_FILTERING           = BASE + 84;
343    /* Clear packet filter */
344    static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
345    /* Set suspend mode optimizations in the driver */
346    static final int CMD_SET_SUSPEND_OPTIMIZATIONS        = BASE + 86;
347    /* Clear suspend mode optimizations in the driver */
348    static final int CMD_CLEAR_SUSPEND_OPTIMIZATIONS      = BASE + 87;
349    /* When there are no saved networks, we do a periodic scan to notify user of
350     * an open network */
351    static final int CMD_NO_NETWORKS_PERIODIC_SCAN        = BASE + 88;
352
353    /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
354    static final int MULTICAST_V6  = 1;
355    static final int MULTICAST_V4  = 0;
356
357   /* Set the frequency band */
358    static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
359    /* Enable background scan for configured networks */
360    static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
361
362    /* Commands from/to the SupplicantStateTracker */
363    /* Reset the supplicant state tracker */
364    static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
365
366    /* P2p commands */
367    public static final int CMD_ENABLE_P2P                = BASE + 131;
368    public static final int CMD_DISABLE_P2P               = BASE + 132;
369
370    private static final int CONNECT_MODE   = 1;
371    private static final int SCAN_ONLY_MODE = 2;
372
373    private static final int SCAN_ACTIVE = 1;
374    private static final int SCAN_PASSIVE = 2;
375
376    private static final int SUCCESS = 1;
377    private static final int FAILURE = -1;
378
379    /* Phone in emergency call back mode */
380    private static final int IN_ECM_STATE = 1;
381    private static final int NOT_IN_ECM_STATE = 0;
382
383    /**
384     * The maximum number of times we will retry a connection to an access point
385     * for which we have failed in acquiring an IP address from DHCP. A value of
386     * N means that we will make N+1 connection attempts in all.
387     * <p>
388     * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
389     * value if a Settings value is not present.
390     */
391    private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
392
393    /* Tracks if power save is enabled in driver */
394    private boolean mPowerSaveEnabled = true;;
395
396    /**
397     * Default framework scan interval in milliseconds. This is used in the scenario in which
398     * wifi chipset does not support background scanning to set up a
399     * periodic wake up scan so that the device can connect to a new access
400     * point on the move. {@link Settings.Secure#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
401     * override this.
402     */
403    private final int mDefaultFrameworkScanIntervalMs;
404
405    /**
406     * Supplicant scan interval in milliseconds.
407     * Comes from {@link Settings.Secure#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
408     * from the default config if the setting is not set
409     */
410    private long mSupplicantScanIntervalMs;
411
412    /**
413     * Minimum time interval between enabling all networks.
414     * A device can end up repeatedly connecting to a bad network on screen on/off toggle
415     * due to enabling every time. We add a threshold to avoid this.
416     */
417    private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
418    private long mLastEnableAllNetworksTime;
419
420    /**
421     * Starting and shutting down driver too quick causes problems leading to driver
422     * being in a bad state. Delay driver stop.
423     */
424    private final int mDriverStopDelayMs;
425    private int mDelayedStopCounter;
426    private boolean mInDelayedStop = false;
427
428    private static final int MIN_RSSI = -200;
429    private static final int MAX_RSSI = 256;
430
431    /* Default parent state */
432    private State mDefaultState = new DefaultState();
433    /* Temporary initial state */
434    private State mInitialState = new InitialState();
435    /* Unloading the driver */
436    private State mDriverUnloadingState = new DriverUnloadingState();
437    /* Loading the driver */
438    private State mDriverUnloadedState = new DriverUnloadedState();
439    /* Driver load/unload failed */
440    private State mDriverFailedState = new DriverFailedState();
441    /* Driver loading */
442    private State mDriverLoadingState = new DriverLoadingState();
443    /* Driver loaded */
444    private State mDriverLoadedState = new DriverLoadedState();
445    /* Driver loaded, waiting for supplicant to start */
446    private State mSupplicantStartingState = new SupplicantStartingState();
447    /* Driver loaded and supplicant ready */
448    private State mSupplicantStartedState = new SupplicantStartedState();
449    /* Waiting for supplicant to stop and monitor to exit */
450    private State mSupplicantStoppingState = new SupplicantStoppingState();
451    /* Driver start issued, waiting for completed event */
452    private State mDriverStartingState = new DriverStartingState();
453    /* Driver started */
454    private State mDriverStartedState = new DriverStartedState();
455    /* Driver stopping */
456    private State mDriverStoppingState = new DriverStoppingState();
457    /* Driver stopped */
458    private State mDriverStoppedState = new DriverStoppedState();
459    /* Scan for networks, no connection will be established */
460    private State mScanModeState = new ScanModeState();
461    /* Connecting to an access point */
462    private State mConnectModeState = new ConnectModeState();
463    /* Connected at 802.11 (L2) level */
464    private State mL2ConnectedState = new L2ConnectedState();
465    /* fetching IP after connection to access point (assoc+auth complete) */
466    private State mObtainingIpState = new ObtainingIpState();
467    /* Waiting for link quality verification to be complete */
468    private State mVerifyingLinkState = new VerifyingLinkState();
469    /* Connected with IP addr */
470    private State mConnectedState = new ConnectedState();
471    /* disconnect issued, waiting for network disconnect confirmation */
472    private State mDisconnectingState = new DisconnectingState();
473    /* Network is not connected, supplicant assoc+auth is not complete */
474    private State mDisconnectedState = new DisconnectedState();
475    /* Waiting for WPS to be completed*/
476    private State mWpsRunningState = new WpsRunningState();
477
478    /* Soft ap is starting up */
479    private State mSoftApStartingState = new SoftApStartingState();
480    /* Soft ap is running */
481    private State mSoftApStartedState = new SoftApStartedState();
482    /* Soft ap is running and we are waiting for tether notification */
483    private State mTetheringState = new TetheringState();
484    /* Soft ap is running and we are tethered through connectivity service */
485    private State mTetheredState = new TetheredState();
486    /* Waiting for untether confirmation to stop soft Ap */
487    private State mSoftApStoppingState = new SoftApStoppingState();
488
489    private class TetherStateChange {
490        ArrayList<String> available;
491        ArrayList<String> active;
492        TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
493            available = av;
494            active = ac;
495        }
496    }
497
498
499    /**
500     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
501     *         {@link WifiManager#WIFI_STATE_DISABLING},
502     *         {@link WifiManager#WIFI_STATE_ENABLED},
503     *         {@link WifiManager#WIFI_STATE_ENABLING},
504     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
505     *
506     */
507    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
508
509    /**
510     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
511     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
512     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
513     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
514     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
515     *
516     */
517    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
518
519    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
520    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
521
522    private static final int SCAN_REQUEST = 0;
523    private static final String ACTION_START_SCAN =
524        "com.android.server.WifiManager.action.START_SCAN";
525
526    private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
527    private static final int DRIVER_STOP_REQUEST = 0;
528    private static final String ACTION_DELAYED_DRIVER_STOP =
529        "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
530
531    /**
532     * Keep track of whether WIFI is running.
533     */
534    private boolean mIsRunning = false;
535
536    /**
537     * Keep track of whether we last told the battery stats we had started.
538     */
539    private boolean mReportedRunning = false;
540
541    /**
542     * Most recently set source of starting WIFI.
543     */
544    private final WorkSource mRunningWifiUids = new WorkSource();
545
546    /**
547     * The last reported UIDs that were responsible for starting WIFI.
548     */
549    private final WorkSource mLastRunningWifiUids = new WorkSource();
550
551    private final IBatteryStats mBatteryStats;
552
553    public WifiStateMachine(Context context, String wlanInterface) {
554        super(TAG);
555
556        mContext = context;
557        mInterfaceName = wlanInterface;
558
559        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
560        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
561
562        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
563        mNwService = INetworkManagementService.Stub.asInterface(b);
564
565        mP2pSupported = mContext.getPackageManager().hasSystemFeature(
566                PackageManager.FEATURE_WIFI_DIRECT);
567
568        mWifiNative = new WifiNative(mInterfaceName);
569        mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
570        mWifiMonitor = new WifiMonitor(this, mWifiNative);
571        mDhcpInfoInternal = new DhcpInfoInternal();
572        mWifiInfo = new WifiInfo();
573        mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
574                getHandler());
575        mLinkProperties = new LinkProperties();
576
577        WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
578                context, getHandler());
579        wifiApConfigStore.loadApConfiguration();
580        mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());
581
582        mNetworkInfo.setIsAvailable(false);
583        mLinkProperties.clear();
584        mLastBssid = null;
585        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
586        mLastSignalLevel = -1;
587
588        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
589        Intent scanIntent = new Intent(ACTION_START_SCAN, null);
590        mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
591
592        mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
593                com.android.internal.R.integer.config_wifi_framework_scan_interval);
594
595        mDriverStopDelayMs = mContext.getResources().getInteger(
596                com.android.internal.R.integer.config_wifi_driver_stop_delay);
597
598        mBackgroundScanSupported = mContext.getResources().getBoolean(
599                com.android.internal.R.bool.config_wifi_background_scan_support);
600
601        mPrimaryDeviceType = mContext.getResources().getString(
602                com.android.internal.R.string.config_wifi_p2p_device_type);
603
604        mContext.registerReceiver(
605            new BroadcastReceiver() {
606                @Override
607                public void onReceive(Context context, Intent intent) {
608                    ArrayList<String> available = intent.getStringArrayListExtra(
609                            ConnectivityManager.EXTRA_AVAILABLE_TETHER);
610                    ArrayList<String> active = intent.getStringArrayListExtra(
611                            ConnectivityManager.EXTRA_ACTIVE_TETHER);
612                    sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
613                }
614            },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
615
616        mContext.registerReceiver(
617                new BroadcastReceiver() {
618                    @Override
619                    public void onReceive(Context context, Intent intent) {
620                        startScan(false);
621                    }
622                },
623                new IntentFilter(ACTION_START_SCAN));
624
625        mScreenFilter = new IntentFilter();
626        mScreenFilter.addAction(Intent.ACTION_SCREEN_ON);
627        mScreenFilter.addAction(Intent.ACTION_SCREEN_OFF);
628        mScreenReceiver = new BroadcastReceiver() {
629            @Override
630            public void onReceive(Context context, Intent intent) {
631                String action = intent.getAction();
632
633                if (action.equals(Intent.ACTION_SCREEN_ON)) {
634                    enableRssiPolling(true);
635                    if (mBackgroundScanSupported) {
636                        enableBackgroundScanCommand(false);
637                    }
638                    enableAllNetworks();
639                    sendMessage(CMD_CLEAR_SUSPEND_OPTIMIZATIONS);
640                } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
641                    enableRssiPolling(false);
642                    if (mBackgroundScanSupported) {
643                        enableBackgroundScanCommand(true);
644                    }
645                    //Allow 2s for suspend optimizations to be set
646                    mSuspendWakeLock.acquire(2000);
647                    sendMessage(CMD_SET_SUSPEND_OPTIMIZATIONS);
648                }
649            }
650        };
651        mContext.registerReceiver(
652                new BroadcastReceiver() {
653                    @Override
654                    public void onReceive(Context context, Intent intent) {
655                       int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
656                       sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, counter, 0));
657                    }
658                },
659                new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
660
661        mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
662
663        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
664        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
665
666        mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
667        mSuspendWakeLock.setReferenceCounted(false);
668
669        addState(mDefaultState);
670            addState(mInitialState, mDefaultState);
671            addState(mDriverUnloadingState, mDefaultState);
672            addState(mDriverUnloadedState, mDefaultState);
673                addState(mDriverFailedState, mDriverUnloadedState);
674            addState(mDriverLoadingState, mDefaultState);
675            addState(mDriverLoadedState, mDefaultState);
676            addState(mSupplicantStartingState, mDefaultState);
677            addState(mSupplicantStartedState, mDefaultState);
678                addState(mDriverStartingState, mSupplicantStartedState);
679                addState(mDriverStartedState, mSupplicantStartedState);
680                    addState(mScanModeState, mDriverStartedState);
681                    addState(mConnectModeState, mDriverStartedState);
682                        addState(mL2ConnectedState, mConnectModeState);
683                            addState(mObtainingIpState, mL2ConnectedState);
684                            addState(mVerifyingLinkState, mL2ConnectedState);
685                            addState(mConnectedState, mL2ConnectedState);
686                        addState(mDisconnectingState, mConnectModeState);
687                        addState(mDisconnectedState, mConnectModeState);
688                        addState(mWpsRunningState, mConnectModeState);
689                addState(mDriverStoppingState, mSupplicantStartedState);
690                addState(mDriverStoppedState, mSupplicantStartedState);
691            addState(mSupplicantStoppingState, mDefaultState);
692            addState(mSoftApStartingState, mDefaultState);
693            addState(mSoftApStartedState, mDefaultState);
694                addState(mTetheringState, mSoftApStartedState);
695                addState(mTetheredState, mSoftApStartedState);
696            addState(mSoftApStoppingState, mDefaultState);
697
698        setInitialState(mInitialState);
699
700        setLogRecSize(100);
701        if (DBG) setDbg(true);
702
703        //start the state machine
704        start();
705    }
706
707    /*********************************************************
708     * Methods exposed for public use
709     ********************************************************/
710
711    public Messenger getMessenger() {
712        return new Messenger(getHandler());
713    }
714    /**
715     * TODO: doc
716     */
717    public boolean syncPingSupplicant(AsyncChannel channel) {
718        Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
719        boolean result = (resultMsg.arg1 != FAILURE);
720        resultMsg.recycle();
721        return result;
722    }
723
724    /**
725     * TODO: doc
726     */
727    public void startScan(boolean forceActive) {
728        sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
729                SCAN_ACTIVE : SCAN_PASSIVE, 0));
730    }
731
732    /**
733     * TODO: doc
734     */
735    public void setWifiEnabled(boolean enable) {
736        mLastEnableUid.set(Binder.getCallingUid());
737        if (enable) {
738            /* Argument is the state that is entered prior to load */
739            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
740            sendMessage(CMD_START_SUPPLICANT);
741        } else {
742            sendMessage(CMD_STOP_SUPPLICANT);
743            /* Argument is the state that is entered upon success */
744            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
745        }
746    }
747
748    /**
749     * TODO: doc
750     */
751    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
752        mLastApEnableUid.set(Binder.getCallingUid());
753        if (enable) {
754            /* Argument is the state that is entered prior to load */
755            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
756            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
757        } else {
758            sendMessage(CMD_STOP_AP);
759            /* Argument is the state that is entered upon success */
760            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
761        }
762    }
763
764    public void setWifiApConfiguration(WifiConfiguration config) {
765        mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
766    }
767
768    public WifiConfiguration syncGetWifiApConfiguration() {
769        Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
770        WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
771        resultMsg.recycle();
772        return ret;
773    }
774
775    /**
776     * TODO: doc
777     */
778    public int syncGetWifiState() {
779        return mWifiState.get();
780    }
781
782    /**
783     * TODO: doc
784     */
785    public String syncGetWifiStateByName() {
786        switch (mWifiState.get()) {
787            case WIFI_STATE_DISABLING:
788                return "disabling";
789            case WIFI_STATE_DISABLED:
790                return "disabled";
791            case WIFI_STATE_ENABLING:
792                return "enabling";
793            case WIFI_STATE_ENABLED:
794                return "enabled";
795            case WIFI_STATE_UNKNOWN:
796                return "unknown state";
797            default:
798                return "[invalid state]";
799        }
800    }
801
802    /**
803     * TODO: doc
804     */
805    public int syncGetWifiApState() {
806        return mWifiApState.get();
807    }
808
809    /**
810     * TODO: doc
811     */
812    public String syncGetWifiApStateByName() {
813        switch (mWifiApState.get()) {
814            case WIFI_AP_STATE_DISABLING:
815                return "disabling";
816            case WIFI_AP_STATE_DISABLED:
817                return "disabled";
818            case WIFI_AP_STATE_ENABLING:
819                return "enabling";
820            case WIFI_AP_STATE_ENABLED:
821                return "enabled";
822            case WIFI_AP_STATE_FAILED:
823                return "failed";
824            default:
825                return "[invalid state]";
826        }
827    }
828
829    /**
830     * Get status information for the current connection, if any.
831     * @return a {@link WifiInfo} object containing information about the current connection
832     *
833     */
834    public WifiInfo syncRequestConnectionInfo() {
835        return mWifiInfo;
836    }
837
838    public DhcpInfo syncGetDhcpInfo() {
839        synchronized (mDhcpInfoInternal) {
840            return mDhcpInfoInternal.makeDhcpInfo();
841        }
842    }
843
844    /**
845     * TODO: doc
846     */
847    public void setDriverStart(boolean enable, boolean ecm) {
848        if (enable) {
849            sendMessage(CMD_START_DRIVER);
850        } else {
851            sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0));
852        }
853    }
854
855    /**
856     * TODO: doc
857     */
858    public void setScanOnlyMode(boolean enable) {
859      if (enable) {
860          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
861      } else {
862          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
863      }
864    }
865
866    /**
867     * TODO: doc
868     */
869    public void setScanType(boolean active) {
870      if (active) {
871          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
872      } else {
873          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
874      }
875    }
876
877    /**
878     * TODO: doc
879     */
880    public List<ScanResult> syncGetScanResultsList() {
881        return mScanResults;
882    }
883
884    /**
885     * Disconnect from Access Point
886     */
887    public void disconnectCommand() {
888        sendMessage(CMD_DISCONNECT);
889    }
890
891    /**
892     * Initiate a reconnection to AP
893     */
894    public void reconnectCommand() {
895        sendMessage(CMD_RECONNECT);
896    }
897
898    /**
899     * Initiate a re-association to AP
900     */
901    public void reassociateCommand() {
902        sendMessage(CMD_REASSOCIATE);
903    }
904
905    /**
906     * Add a network synchronously
907     *
908     * @return network id of the new network
909     */
910    public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
911        Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
912        int result = resultMsg.arg1;
913        resultMsg.recycle();
914        return result;
915    }
916
917    public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) {
918        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS);
919        List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
920        resultMsg.recycle();
921        return result;
922    }
923
924    /**
925     * Delete a network
926     *
927     * @param networkId id of the network to be removed
928     */
929    public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
930        Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
931        boolean result = (resultMsg.arg1 != FAILURE);
932        resultMsg.recycle();
933        return result;
934    }
935
936    /**
937     * Enable a network
938     *
939     * @param netId network id of the network
940     * @param disableOthers true, if all other networks have to be disabled
941     * @return {@code true} if the operation succeeds, {@code false} otherwise
942     */
943    public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
944        Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
945                disableOthers ? 1 : 0);
946        boolean result = (resultMsg.arg1 != FAILURE);
947        resultMsg.recycle();
948        return result;
949    }
950
951    /**
952     * Disable a network
953     *
954     * @param netId network id of the network
955     * @return {@code true} if the operation succeeds, {@code false} otherwise
956     */
957    public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
958        Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
959        boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
960        resultMsg.recycle();
961        return result;
962    }
963
964    /**
965     * Blacklist a BSSID. This will avoid the AP if there are
966     * alternate APs to connect
967     *
968     * @param bssid BSSID of the network
969     */
970    public void addToBlacklist(String bssid) {
971        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
972    }
973
974    /**
975     * Clear the blacklist list
976     *
977     */
978    public void clearBlacklist() {
979        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
980    }
981
982    public void enableRssiPolling(boolean enabled) {
983       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
984    }
985
986    public void enableBackgroundScanCommand(boolean enabled) {
987       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
988    }
989
990    public void enableAllNetworks() {
991        sendMessage(CMD_ENABLE_ALL_NETWORKS);
992    }
993
994    /**
995     * Start filtering Multicast v4 packets
996     */
997    public void startFilteringMulticastV4Packets() {
998        mFilteringMulticastV4Packets.set(true);
999        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0));
1000    }
1001
1002    /**
1003     * Stop filtering Multicast v4 packets
1004     */
1005    public void stopFilteringMulticastV4Packets() {
1006        mFilteringMulticastV4Packets.set(false);
1007        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0));
1008    }
1009
1010    /**
1011     * Start filtering Multicast v4 packets
1012     */
1013    public void startFilteringMulticastV6Packets() {
1014        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0));
1015    }
1016
1017    /**
1018     * Stop filtering Multicast v4 packets
1019     */
1020    public void stopFilteringMulticastV6Packets() {
1021        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0));
1022    }
1023
1024    /**
1025     * Set high performance mode of operation.
1026     * Enabling would set active power mode and disable suspend optimizations;
1027     * disabling would set auto power mode and enable suspend optimizations
1028     * @param enable true if enable, false otherwise
1029     */
1030    public void setHighPerfModeEnabled(boolean enable) {
1031        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
1032    }
1033
1034    /**
1035     * Set the country code
1036     * @param countryCode following ISO 3166 format
1037     * @param persist {@code true} if the setting should be remembered.
1038     */
1039    public void setCountryCode(String countryCode, boolean persist) {
1040        if (persist) {
1041            Settings.Secure.putString(mContext.getContentResolver(),
1042                    Settings.Secure.WIFI_COUNTRY_CODE,
1043                    countryCode);
1044        }
1045        sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
1046    }
1047
1048    /**
1049     * Set the operational frequency band
1050     * @param band
1051     * @param persist {@code true} if the setting should be remembered.
1052     */
1053    public void setFrequencyBand(int band, boolean persist) {
1054        if (persist) {
1055            Settings.Secure.putInt(mContext.getContentResolver(),
1056                    Settings.Secure.WIFI_FREQUENCY_BAND,
1057                    band);
1058        }
1059        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
1060    }
1061
1062    /**
1063     * Returns the operational frequency band
1064     */
1065    public int getFrequencyBand() {
1066        return mFrequencyBand.get();
1067    }
1068
1069    /**
1070     * Returns the wifi configuration file
1071     */
1072    public String getConfigFile() {
1073        return mWifiConfigStore.getConfigFile();
1074    }
1075
1076    /**
1077     * Send a message indicating bluetooth adapter connection state changed
1078     */
1079    public void sendBluetoothAdapterStateChange(int state) {
1080        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
1081    }
1082
1083    /**
1084     * Save configuration on supplicant
1085     *
1086     * @return {@code true} if the operation succeeds, {@code false} otherwise
1087     *
1088     * TODO: deprecate this
1089     */
1090    public boolean syncSaveConfig(AsyncChannel channel) {
1091        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
1092        boolean result = (resultMsg.arg1 != FAILURE);
1093        resultMsg.recycle();
1094        return result;
1095    }
1096
1097    public void updateBatteryWorkSource(WorkSource newSource) {
1098        synchronized (mRunningWifiUids) {
1099            try {
1100                if (newSource != null) {
1101                    mRunningWifiUids.set(newSource);
1102                }
1103                if (mIsRunning) {
1104                    if (mReportedRunning) {
1105                        // If the work source has changed since last time, need
1106                        // to remove old work from battery stats.
1107                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
1108                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
1109                                    mRunningWifiUids);
1110                            mLastRunningWifiUids.set(mRunningWifiUids);
1111                        }
1112                    } else {
1113                        // Now being started, report it.
1114                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
1115                        mLastRunningWifiUids.set(mRunningWifiUids);
1116                        mReportedRunning = true;
1117                    }
1118                } else {
1119                    if (mReportedRunning) {
1120                        // Last reported we were running, time to stop.
1121                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
1122                        mLastRunningWifiUids.clear();
1123                        mReportedRunning = false;
1124                    }
1125                }
1126                mWakeLock.setWorkSource(newSource);
1127            } catch (RemoteException ignore) {
1128            }
1129        }
1130    }
1131
1132    @Override
1133    public String toString() {
1134        StringBuffer sb = new StringBuffer();
1135        String LS = System.getProperty("line.separator");
1136        sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
1137        sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
1138        sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
1139        sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
1140        sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
1141        sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
1142        sb.append("mLastBssid ").append(mLastBssid).append(LS);
1143        sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
1144        sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
1145        sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
1146        sb.append("Supplicant status").append(LS)
1147                .append(mWifiNative.status()).append(LS).append(LS);
1148
1149        sb.append(mWifiConfigStore.dump());
1150        return sb.toString();
1151    }
1152
1153    @Override
1154    protected boolean recordLogRec(Message msg) {
1155        //Ignore screen on/off & common messages when driver has started
1156        if (getCurrentState() == mConnectedState || getCurrentState() == mDisconnectedState) {
1157            switch (msg.what) {
1158                case CMD_LOAD_DRIVER:
1159                case CMD_START_SUPPLICANT:
1160                case CMD_START_DRIVER:
1161                case CMD_SET_SCAN_MODE:
1162                case CMD_SET_HIGH_PERF_MODE:
1163                case CMD_SET_SUSPEND_OPTIMIZATIONS:
1164                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
1165                case CMD_ENABLE_BACKGROUND_SCAN:
1166                case CMD_ENABLE_ALL_NETWORKS:
1167                return false;
1168            }
1169        }
1170
1171        switch (msg.what) {
1172            case CMD_START_SCAN:
1173            case CMD_ENABLE_RSSI_POLL:
1174            case CMD_RSSI_POLL:
1175            case CMD_DELAYED_STOP_DRIVER:
1176            case WifiMonitor.SCAN_RESULTS_EVENT:
1177            case WifiWatchdogStateMachine.RSSI_FETCH:
1178                return false;
1179            default:
1180                return true;
1181        }
1182    }
1183
1184    /*********************************************************
1185     * Internal private functions
1186     ********************************************************/
1187
1188    private void checkAndSetConnectivityInstance() {
1189        if (mCm == null) {
1190            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1191        }
1192    }
1193
1194    private boolean startTethering(ArrayList<String> available) {
1195
1196        boolean wifiAvailable = false;
1197
1198        checkAndSetConnectivityInstance();
1199
1200        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1201
1202        for (String intf : available) {
1203            for (String regex : wifiRegexs) {
1204                if (intf.matches(regex)) {
1205
1206                    InterfaceConfiguration ifcg = null;
1207                    try {
1208                        ifcg = mNwService.getInterfaceConfig(intf);
1209                        if (ifcg != null) {
1210                            /* IP/netmask: 192.168.43.1/255.255.255.0 */
1211                            ifcg.setLinkAddress(new LinkAddress(
1212                                    NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
1213                            ifcg.setInterfaceUp();
1214
1215                            mNwService.setInterfaceConfig(intf, ifcg);
1216                        }
1217                    } catch (Exception e) {
1218                        loge("Error configuring interface " + intf + ", :" + e);
1219                        return false;
1220                    }
1221
1222                    if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1223                        loge("Error tethering on " + intf);
1224                        return false;
1225                    }
1226                    mTetherInterfaceName = intf;
1227                    return true;
1228                }
1229            }
1230        }
1231        // We found no interfaces to tether
1232        return false;
1233    }
1234
1235    private void stopTethering() {
1236
1237        checkAndSetConnectivityInstance();
1238
1239        /* Clear the interface config to allow dhcp correctly configure new
1240           ip settings */
1241        InterfaceConfiguration ifcg = null;
1242        try {
1243            ifcg = mNwService.getInterfaceConfig(mInterfaceName);
1244            if (ifcg != null) {
1245                ifcg.setLinkAddress(
1246                        new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
1247                mNwService.setInterfaceConfig(mInterfaceName, ifcg);
1248            }
1249        } catch (Exception e) {
1250            loge("Error resetting interface " + mInterfaceName + ", :" + e);
1251        }
1252
1253        if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1254            loge("Untether initiate failed!");
1255        }
1256    }
1257
1258    private boolean isWifiTethered(ArrayList<String> active) {
1259
1260        checkAndSetConnectivityInstance();
1261
1262        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1263        for (String intf : active) {
1264            for (String regex : wifiRegexs) {
1265                if (intf.matches(regex)) {
1266                    return true;
1267                }
1268            }
1269        }
1270        // We found no interfaces that are tethered
1271        return false;
1272    }
1273
1274    /**
1275     * Set the country code from the system setting value, if any.
1276     */
1277    private void setCountryCode() {
1278        String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1279                Settings.Secure.WIFI_COUNTRY_CODE);
1280        if (countryCode != null && !countryCode.isEmpty()) {
1281            setCountryCode(countryCode, false);
1282        } else {
1283            //use driver default
1284        }
1285    }
1286
1287    /**
1288     * Set the frequency band from the system setting value, if any.
1289     */
1290    private void setFrequencyBand() {
1291        int band = Settings.Secure.getInt(mContext.getContentResolver(),
1292                Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1293        setFrequencyBand(band, false);
1294    }
1295
1296    private void setWifiState(int wifiState) {
1297        final int previousWifiState = mWifiState.get();
1298
1299        try {
1300            if (wifiState == WIFI_STATE_ENABLED) {
1301                mBatteryStats.noteWifiOn();
1302            } else if (wifiState == WIFI_STATE_DISABLED) {
1303                mBatteryStats.noteWifiOff();
1304            }
1305        } catch (RemoteException e) {
1306            loge("Failed to note battery stats in wifi");
1307        }
1308
1309        mWifiState.set(wifiState);
1310
1311        if (DBG) log("setWifiState: " + syncGetWifiStateByName());
1312
1313        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1314        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1315        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1316        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1317        mContext.sendStickyBroadcast(intent);
1318    }
1319
1320    private void setWifiApState(int wifiApState) {
1321        final int previousWifiApState = mWifiApState.get();
1322
1323        try {
1324            if (wifiApState == WIFI_AP_STATE_ENABLED) {
1325                mBatteryStats.noteWifiOn();
1326            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1327                mBatteryStats.noteWifiOff();
1328            }
1329        } catch (RemoteException e) {
1330            loge("Failed to note battery stats in wifi");
1331        }
1332
1333        // Update state
1334        mWifiApState.set(wifiApState);
1335
1336        if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
1337
1338        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1339        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1340        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1341        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1342        mContext.sendStickyBroadcast(intent);
1343    }
1344
1345    /**
1346     * Parse the scan result line passed to us by wpa_supplicant (helper).
1347     * @param line the line to parse
1348     * @return the {@link ScanResult} object
1349     */
1350    private ScanResult parseScanResult(String line) {
1351        ScanResult scanResult = null;
1352        if (line != null) {
1353            /*
1354             * Cache implementation (LinkedHashMap) is not synchronized, thus,
1355             * must synchronized here!
1356             */
1357            synchronized (mScanResultCache) {
1358                String[] result = scanResultPattern.split(line);
1359                if (3 <= result.length && result.length <= 5) {
1360                    String bssid = result[0];
1361                    // bssid | frequency | level | flags | ssid
1362                    int frequency;
1363                    int level;
1364                    try {
1365                        frequency = Integer.parseInt(result[1]);
1366                        level = Integer.parseInt(result[2]);
1367                        /* some implementations avoid negative values by adding 256
1368                         * so we need to adjust for that here.
1369                         */
1370                        if (level > 0) level -= 256;
1371                    } catch (NumberFormatException e) {
1372                        frequency = 0;
1373                        level = 0;
1374                    }
1375
1376                    /*
1377                     * The formatting of the results returned by
1378                     * wpa_supplicant is intended to make the fields
1379                     * line up nicely when printed,
1380                     * not to make them easy to parse. So we have to
1381                     * apply some heuristics to figure out which field
1382                     * is the SSID and which field is the flags.
1383                     */
1384                    String ssid;
1385                    String flags;
1386                    if (result.length == 4) {
1387                        if (result[3].charAt(0) == '[') {
1388                            flags = result[3];
1389                            ssid = "";
1390                        } else {
1391                            flags = "";
1392                            ssid = result[3];
1393                        }
1394                    } else if (result.length == 5) {
1395                        flags = result[3];
1396                        ssid = result[4];
1397                    } else {
1398                        // Here, we must have 3 fields: no flags and ssid
1399                        // set
1400                        flags = "";
1401                        ssid = "";
1402                    }
1403
1404                    // bssid + ssid is the hash key
1405                    String key = bssid + ssid;
1406                    scanResult = mScanResultCache.get(key);
1407                    if (scanResult != null) {
1408                        scanResult.level = level;
1409                        scanResult.SSID = ssid;
1410                        scanResult.capabilities = flags;
1411                        scanResult.frequency = frequency;
1412                    } else {
1413                        // Do not add scan results that have no SSID set
1414                        if (0 < ssid.trim().length()) {
1415                            scanResult =
1416                                new ScanResult(
1417                                    ssid, bssid, flags, level, frequency);
1418                            mScanResultCache.put(key, scanResult);
1419                        }
1420                    }
1421                } else {
1422                    loge("Misformatted scan result text with " +
1423                          result.length + " fields: " + line);
1424                }
1425            }
1426        }
1427
1428        return scanResult;
1429    }
1430
1431    /**
1432     * scanResults input format
1433     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
1434     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
1435     */
1436    private void setScanResults(String scanResults) {
1437        if (scanResults == null) {
1438            return;
1439        }
1440
1441        List<ScanResult> scanList = new ArrayList<ScanResult>();
1442
1443        int lineCount = 0;
1444
1445        int scanResultsLen = scanResults.length();
1446        // Parse the result string, keeping in mind that the last line does
1447        // not end with a newline.
1448        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
1449            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
1450                ++lineCount;
1451
1452                if (lineCount == 1) {
1453                    lineBeg = lineEnd + 1;
1454                    continue;
1455                }
1456                if (lineEnd > lineBeg) {
1457                    String line = scanResults.substring(lineBeg, lineEnd);
1458                    ScanResult scanResult = parseScanResult(line);
1459                    if (scanResult != null) {
1460                        scanList.add(scanResult);
1461                    } else {
1462                        //TODO: hidden network handling
1463                    }
1464                }
1465                lineBeg = lineEnd + 1;
1466            }
1467        }
1468
1469        mScanResults = scanList;
1470    }
1471
1472    /*
1473     * Fetch RSSI and linkspeed on current connection
1474     */
1475    private void fetchRssiAndLinkSpeedNative() {
1476        int newRssi = -1;
1477        int newLinkSpeed = -1;
1478
1479        String signalPoll = mWifiNative.signalPoll();
1480
1481        if (signalPoll != null) {
1482            String[] lines = signalPoll.split("\n");
1483            for (String line : lines) {
1484                String[] prop = line.split("=");
1485                if (prop.length < 2) continue;
1486                try {
1487                    if (prop[0].equals("RSSI")) {
1488                        newRssi = Integer.parseInt(prop[1]);
1489                    } else if (prop[0].equals("LINKSPEED")) {
1490                        newLinkSpeed = Integer.parseInt(prop[1]);
1491                    }
1492                } catch (NumberFormatException e) {
1493                    //Ignore, defaults on rssi and linkspeed are assigned
1494                }
1495            }
1496        }
1497
1498        if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1499            /* some implementations avoid negative values by adding 256
1500             * so we need to adjust for that here.
1501             */
1502            if (newRssi > 0) newRssi -= 256;
1503            mWifiInfo.setRssi(newRssi);
1504            /*
1505             * Rather then sending the raw RSSI out every time it
1506             * changes, we precalculate the signal level that would
1507             * be displayed in the status bar, and only send the
1508             * broadcast if that much more coarse-grained number
1509             * changes. This cuts down greatly on the number of
1510             * broadcasts, at the cost of not informing others
1511             * interested in RSSI of all the changes in signal
1512             * level.
1513             */
1514            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
1515            if (newSignalLevel != mLastSignalLevel) {
1516                sendRssiChangeBroadcast(newRssi);
1517            }
1518            mLastSignalLevel = newSignalLevel;
1519        } else {
1520            mWifiInfo.setRssi(MIN_RSSI);
1521        }
1522
1523        if (newLinkSpeed != -1) {
1524            mWifiInfo.setLinkSpeed(newLinkSpeed);
1525        }
1526    }
1527
1528    private void configureLinkProperties() {
1529        if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1530            mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId);
1531        } else {
1532            synchronized (mDhcpInfoInternal) {
1533                mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1534            }
1535            mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1536        }
1537        mLinkProperties.setInterfaceName(mInterfaceName);
1538        if (DBG) {
1539            log("netId=" + mLastNetworkId  + " Link configured: " +
1540                    mLinkProperties.toString());
1541        }
1542    }
1543
1544    private int getMaxDhcpRetries() {
1545        return Settings.Secure.getInt(mContext.getContentResolver(),
1546                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1547                                      DEFAULT_MAX_DHCP_RETRIES);
1548    }
1549
1550    private void sendScanResultsAvailableBroadcast() {
1551        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1552        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1553        mContext.sendBroadcast(intent);
1554    }
1555
1556    private void sendRssiChangeBroadcast(final int newRssi) {
1557        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1558        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1559        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1560        mContext.sendBroadcast(intent);
1561    }
1562
1563    private void sendNetworkStateChangeBroadcast(String bssid) {
1564        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1565        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1566        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
1567        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1568        if (bssid != null)
1569            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1570        if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
1571                mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
1572            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
1573        }
1574        mContext.sendStickyBroadcast(intent);
1575    }
1576
1577    private void sendLinkConfigurationChangedBroadcast() {
1578        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1579        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1580        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1581        mContext.sendBroadcast(intent);
1582    }
1583
1584    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1585        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1586        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1587        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1588        mContext.sendBroadcast(intent);
1589    }
1590
1591    /**
1592     * Record the detailed state of a network.
1593     * @param state the new @{code DetailedState}
1594     */
1595    private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1596        if (DBG) {
1597            log("setDetailed state, old ="
1598                    + mNetworkInfo.getDetailedState() + " and new state=" + state);
1599        }
1600
1601        if (state != mNetworkInfo.getDetailedState()) {
1602            mNetworkInfo.setDetailedState(state, null, null);
1603        }
1604    }
1605
1606    private DetailedState getNetworkDetailedState() {
1607        return mNetworkInfo.getDetailedState();
1608    }
1609
1610
1611    private SupplicantState handleSupplicantStateChange(Message message) {
1612        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
1613        SupplicantState state = stateChangeResult.state;
1614        // Supplicant state change
1615        // [31-13] Reserved for future use
1616        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
1617        // 50023 supplicant_state_changed (custom|1|5)
1618        EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
1619        mWifiInfo.setSupplicantState(state);
1620        // Network id is only valid when we start connecting
1621        if (SupplicantState.isConnecting(state)) {
1622            mWifiInfo.setNetworkId(stateChangeResult.networkId);
1623        } else {
1624            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1625        }
1626
1627        if (state == SupplicantState.ASSOCIATING) {
1628            /* BSSID is valid only in ASSOCIATING state */
1629            mWifiInfo.setBSSID(stateChangeResult.BSSID);
1630        }
1631        mWifiInfo.setSSID(stateChangeResult.SSID);
1632
1633        mSupplicantStateTracker.sendMessage(Message.obtain(message));
1634
1635        return state;
1636    }
1637
1638    /**
1639     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1640     * using the interface, stopping DHCP & disabling interface
1641     */
1642    private void handleNetworkDisconnect() {
1643        if (DBG) log("Stopping DHCP and clearing IP");
1644
1645        /*
1646         * stop DHCP
1647         */
1648        if (mDhcpStateMachine != null) {
1649            /* In case we were in middle of DHCP operation
1650               restore back powermode */
1651            handlePostDhcpSetup();
1652
1653            mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1654            mDhcpStateMachine.doQuit();
1655            mDhcpStateMachine = null;
1656        }
1657
1658        try {
1659            mNwService.clearInterfaceAddresses(mInterfaceName);
1660            mNwService.disableIpv6(mInterfaceName);
1661        } catch (Exception e) {
1662            loge("Failed to clear addresses or disable ipv6" + e);
1663        }
1664
1665        /* Reset data structures */
1666        mWifiInfo.setInetAddress(null);
1667        mWifiInfo.setBSSID(null);
1668        mWifiInfo.setSSID(null);
1669        mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1670        mWifiInfo.setRssi(MIN_RSSI);
1671        mWifiInfo.setLinkSpeed(-1);
1672        mWifiInfo.setMeteredHint(false);
1673
1674        setNetworkDetailedState(DetailedState.DISCONNECTED);
1675        mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
1676
1677        /* send event to CM & network change broadcast */
1678        sendNetworkStateChangeBroadcast(mLastBssid);
1679
1680        /* Clear network properties */
1681        mLinkProperties.clear();
1682        /* Clear IP settings if the network used DHCP */
1683        if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1684            mWifiConfigStore.clearIpConfiguration(mLastNetworkId);
1685        }
1686
1687        mLastBssid= null;
1688        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1689    }
1690
1691    void handlePreDhcpSetup() {
1692        if (!mBluetoothConnectionActive) {
1693            /*
1694             * There are problems setting the Wi-Fi driver's power
1695             * mode to active when bluetooth coexistence mode is
1696             * enabled or sense.
1697             * <p>
1698             * We set Wi-Fi to active mode when
1699             * obtaining an IP address because we've found
1700             * compatibility issues with some routers with low power
1701             * mode.
1702             * <p>
1703             * In order for this active power mode to properly be set,
1704             * we disable coexistence mode until we're done with
1705             * obtaining an IP address.  One exception is if we
1706             * are currently connected to a headset, since disabling
1707             * coexistence would interrupt that connection.
1708             */
1709            // Disable the coexistence mode
1710            mWifiNative.setBluetoothCoexistenceMode(
1711                    mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1712        }
1713
1714        /* Disable power save during DHCP */
1715        if (mPowerSaveEnabled) {
1716            mPowerSaveEnabled = false;
1717            mWifiNative.setPowerSave(mPowerSaveEnabled);
1718        }
1719    }
1720
1721
1722    void handlePostDhcpSetup() {
1723        /* Restore power save */
1724        mPowerSaveEnabled = true;
1725        mWifiNative.setPowerSave(mPowerSaveEnabled);
1726
1727        // Set the coexistence mode back to its default value
1728        mWifiNative.setBluetoothCoexistenceMode(
1729                mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1730    }
1731
1732    private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
1733        synchronized (mDhcpInfoInternal) {
1734            mDhcpInfoInternal = dhcpInfoInternal;
1735        }
1736        mLastSignalLevel = -1; // force update of signal strength
1737        mReconnectCount = 0; //Reset IP failure tracking
1738        mWifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
1739        InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
1740        mWifiInfo.setInetAddress(addr);
1741        mWifiInfo.setMeteredHint(dhcpInfoInternal.hasMeteredHint());
1742        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1743            //DHCP renewal in connected state
1744            LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
1745            linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1746            linkProperties.setInterfaceName(mInterfaceName);
1747            if (!linkProperties.equals(mLinkProperties)) {
1748                if (DBG) {
1749                    log("Link configuration changed for netId: " + mLastNetworkId
1750                            + " old: " + mLinkProperties + "new: " + linkProperties);
1751                }
1752                mLinkProperties = linkProperties;
1753                sendLinkConfigurationChangedBroadcast();
1754            }
1755        } else {
1756            configureLinkProperties();
1757        }
1758    }
1759
1760    private void handleFailedIpConfiguration() {
1761        loge("IP configuration failed");
1762
1763        mWifiInfo.setInetAddress(null);
1764        mWifiInfo.setMeteredHint(false);
1765        /**
1766         * If we've exceeded the maximum number of retries for DHCP
1767         * to a given network, disable the network
1768         */
1769        int maxRetries = getMaxDhcpRetries();
1770        // maxRetries == 0 means keep trying forever
1771        if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
1772            loge("Failed " +
1773                    mReconnectCount + " times, Disabling " + mLastNetworkId);
1774            mWifiConfigStore.disableNetwork(mLastNetworkId,
1775                    WifiConfiguration.DISABLED_DHCP_FAILURE);
1776            mReconnectCount = 0;
1777        }
1778
1779        /* DHCP times out after about 30 seconds, we do a
1780         * disconnect and an immediate reconnect to try again
1781         */
1782        mWifiNative.disconnect();
1783        mWifiNative.reconnect();
1784    }
1785
1786    /* Current design is to not set the config on a running hostapd but instead
1787     * stop and start tethering when user changes config on a running access point
1788     *
1789     * TODO: Add control channel setup through hostapd that allows changing config
1790     * on a running daemon
1791     */
1792    private void startSoftApWithConfig(final WifiConfiguration config) {
1793        // start hostapd on a seperate thread
1794        new Thread(new Runnable() {
1795            public void run() {
1796                try {
1797                    mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1798                } catch (Exception e) {
1799                    loge("Exception in softap start " + e);
1800                    try {
1801                        mNwService.stopAccessPoint(mInterfaceName);
1802                        mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1803                    } catch (Exception e1) {
1804                        loge("Exception in softap re-start " + e1);
1805                        sendMessage(CMD_START_AP_FAILURE);
1806                        return;
1807                    }
1808                }
1809                if (DBG) log("Soft AP start successful");
1810                sendMessage(CMD_START_AP_SUCCESS);
1811            }
1812        }).start();
1813    }
1814
1815    /********************************************************
1816     * HSM states
1817     *******************************************************/
1818
1819    class DefaultState extends State {
1820        @Override
1821        public boolean processMessage(Message message) {
1822            if (DBG) log(getName() + message.toString() + "\n");
1823            switch (message.what) {
1824                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1825                    if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1826                        mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1827                    } else {
1828                        loge("WifiP2pService connection failure, error=" + message.arg1);
1829                    }
1830                    break;
1831                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1832                    loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
1833                    //TODO: Re-establish connection to state machine after a delay
1834                    //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
1835                    break;
1836                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1837                    mBluetoothConnectionActive = (message.arg1 !=
1838                            BluetoothAdapter.STATE_DISCONNECTED);
1839                    break;
1840                    /* Synchronous call returns */
1841                case CMD_PING_SUPPLICANT:
1842                case CMD_ENABLE_NETWORK:
1843                case CMD_ADD_OR_UPDATE_NETWORK:
1844                case CMD_REMOVE_NETWORK:
1845                case CMD_SAVE_CONFIG:
1846                    replyToMessage(message, message.what, FAILURE);
1847                    break;
1848                case CMD_GET_CONFIGURED_NETWORKS:
1849                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
1850                    break;
1851                case CMD_ENABLE_RSSI_POLL:
1852                    mEnableRssiPolling = (message.arg1 == 1);
1853                    break;
1854                case CMD_ENABLE_BACKGROUND_SCAN:
1855                    mEnableBackgroundScan = (message.arg1 == 1);
1856                    break;
1857                case CMD_SET_HIGH_PERF_MODE:
1858                    mHighPerfMode = (message.arg1 == 1);
1859                    break;
1860                    /* Discard */
1861                case CMD_LOAD_DRIVER:
1862                case CMD_UNLOAD_DRIVER:
1863                case CMD_START_SUPPLICANT:
1864                case CMD_STOP_SUPPLICANT:
1865                case CMD_STOP_SUPPLICANT_FAILED:
1866                case CMD_START_DRIVER:
1867                case CMD_STOP_DRIVER:
1868                case CMD_DELAYED_STOP_DRIVER:
1869                case CMD_DRIVER_START_TIMED_OUT:
1870                case CMD_START_AP:
1871                case CMD_START_AP_SUCCESS:
1872                case CMD_START_AP_FAILURE:
1873                case CMD_STOP_AP:
1874                case CMD_TETHER_STATE_CHANGE:
1875                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
1876                case CMD_START_SCAN:
1877                case CMD_DISCONNECT:
1878                case CMD_RECONNECT:
1879                case CMD_REASSOCIATE:
1880                case WifiMonitor.SUP_CONNECTION_EVENT:
1881                case WifiMonitor.SUP_DISCONNECTION_EVENT:
1882                case WifiMonitor.NETWORK_CONNECTION_EVENT:
1883                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
1884                case WifiMonitor.SCAN_RESULTS_EVENT:
1885                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
1886                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
1887                case WifiMonitor.WPS_OVERLAP_EVENT:
1888                case CMD_BLACKLIST_NETWORK:
1889                case CMD_CLEAR_BLACKLIST:
1890                case CMD_SET_SCAN_MODE:
1891                case CMD_SET_SCAN_TYPE:
1892                case CMD_SET_COUNTRY_CODE:
1893                case CMD_SET_FREQUENCY_BAND:
1894                case CMD_RSSI_POLL:
1895                case CMD_ENABLE_ALL_NETWORKS:
1896                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1897                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1898                /* Handled by WifiApConfigStore */
1899                case CMD_SET_AP_CONFIG:
1900                case CMD_SET_AP_CONFIG_COMPLETED:
1901                case CMD_REQUEST_AP_CONFIG:
1902                case CMD_RESPONSE_AP_CONFIG:
1903                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
1904                case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
1905                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
1906                case CMD_NO_NETWORKS_PERIODIC_SCAN:
1907                    break;
1908                case CMD_SET_SUSPEND_OPTIMIZATIONS:
1909                    mSuspendWakeLock.release();
1910                    break;
1911                case WifiMonitor.DRIVER_HUNG_EVENT:
1912                    setWifiEnabled(false);
1913                    setWifiEnabled(true);
1914                    break;
1915                case WifiManager.CONNECT_NETWORK:
1916                    replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
1917                            WifiManager.BUSY);
1918                    break;
1919                case WifiManager.FORGET_NETWORK:
1920                    replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
1921                            WifiManager.BUSY);
1922                    break;
1923                case WifiManager.SAVE_NETWORK:
1924                    replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
1925                            WifiManager.BUSY);
1926                    break;
1927                case WifiManager.START_WPS:
1928                    replyToMessage(message, WifiManager.WPS_FAILED,
1929                            WifiManager.BUSY);
1930                    break;
1931                case WifiManager.CANCEL_WPS:
1932                    replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
1933                            WifiManager.BUSY);
1934                    break;
1935                case WifiManager.DISABLE_NETWORK:
1936                    replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
1937                            WifiManager.BUSY);
1938                    break;
1939                case WifiWatchdogStateMachine.RSSI_FETCH:
1940                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_FETCH_FAILED);
1941                    break;
1942                default:
1943                    loge("Error! unhandled message" + message);
1944                    break;
1945            }
1946            return HANDLED;
1947        }
1948    }
1949
1950    class InitialState extends State {
1951        @Override
1952        //TODO: could move logging into a common class
1953        public void enter() {
1954            if (DBG) log(getName() + "\n");
1955            // [31-8] Reserved for future use
1956            // [7 - 0] HSM state change
1957            // 50021 wifi_state_changed (custom|1|5)
1958            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1959
1960            if (mWifiNative.isDriverLoaded()) {
1961                transitionTo(mDriverLoadedState);
1962            }
1963            else {
1964                transitionTo(mDriverUnloadedState);
1965            }
1966
1967            //Connect to WifiP2pService
1968            mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
1969            mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
1970
1971            /* IPv6 is disabled at boot time and is controlled by framework
1972             * to be enabled only as long as we are connected to an access point
1973             *
1974             * This fixes issues, a few being:
1975             * - IPv6 addresses and routes stick around after disconnection
1976             * - When connected, the kernel is unaware and can fail to start IPv6 negotiation
1977             * - The kernel sometimes starts autoconfiguration when 802.1x is not complete
1978             */
1979            try {
1980                mNwService.disableIpv6(mInterfaceName);
1981            } catch (RemoteException re) {
1982                loge("Failed to disable IPv6: " + re);
1983            } catch (IllegalStateException e) {
1984                loge("Failed to disable IPv6: " + e);
1985            }
1986        }
1987    }
1988
1989    class DriverLoadingState extends State {
1990        @Override
1991        public void enter() {
1992            if (DBG) log(getName() + "\n");
1993            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1994
1995            final Message message = new Message();
1996            message.copyFrom(getCurrentMessage());
1997            /* TODO: add a timeout to fail when driver load is hung.
1998             * Similarly for driver unload.
1999             */
2000            new Thread(new Runnable() {
2001                public void run() {
2002                    mWakeLock.acquire();
2003                    //enabling state
2004                    switch(message.arg1) {
2005                        case WIFI_STATE_ENABLING:
2006                            setWifiState(WIFI_STATE_ENABLING);
2007                            break;
2008                        case WIFI_AP_STATE_ENABLING:
2009                            setWifiApState(WIFI_AP_STATE_ENABLING);
2010                            break;
2011                    }
2012
2013                    if(mWifiNative.loadDriver()) {
2014                        if (DBG) log("Driver load successful");
2015                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
2016                    } else {
2017                        loge("Failed to load driver!");
2018                        switch(message.arg1) {
2019                            case WIFI_STATE_ENABLING:
2020                                setWifiState(WIFI_STATE_UNKNOWN);
2021                                break;
2022                            case WIFI_AP_STATE_ENABLING:
2023                                setWifiApState(WIFI_AP_STATE_FAILED);
2024                                break;
2025                        }
2026                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
2027                    }
2028                    mWakeLock.release();
2029                }
2030            }).start();
2031        }
2032
2033        @Override
2034        public boolean processMessage(Message message) {
2035            if (DBG) log(getName() + message.toString() + "\n");
2036            switch (message.what) {
2037                case CMD_LOAD_DRIVER_SUCCESS:
2038                    transitionTo(mDriverLoadedState);
2039                    break;
2040                case CMD_LOAD_DRIVER_FAILURE:
2041                    transitionTo(mDriverFailedState);
2042                    break;
2043                case CMD_LOAD_DRIVER:
2044                case CMD_UNLOAD_DRIVER:
2045                case CMD_START_SUPPLICANT:
2046                case CMD_STOP_SUPPLICANT:
2047                case CMD_START_AP:
2048                case CMD_STOP_AP:
2049                case CMD_START_DRIVER:
2050                case CMD_STOP_DRIVER:
2051                case CMD_SET_SCAN_MODE:
2052                case CMD_SET_SCAN_TYPE:
2053                case CMD_SET_COUNTRY_CODE:
2054                case CMD_SET_FREQUENCY_BAND:
2055                case CMD_START_PACKET_FILTERING:
2056                case CMD_STOP_PACKET_FILTERING:
2057                    deferMessage(message);
2058                    break;
2059                default:
2060                    return NOT_HANDLED;
2061            }
2062            return HANDLED;
2063        }
2064    }
2065
2066    class DriverLoadedState extends State {
2067        @Override
2068        public void enter() {
2069            if (DBG) log(getName() + "\n");
2070            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2071        }
2072        @Override
2073        public boolean processMessage(Message message) {
2074            if (DBG) log(getName() + message.toString() + "\n");
2075            switch(message.what) {
2076                case CMD_UNLOAD_DRIVER:
2077                    transitionTo(mDriverUnloadingState);
2078                    break;
2079                case CMD_START_SUPPLICANT:
2080                    try {
2081                        mNwService.wifiFirmwareReload(mInterfaceName, "STA");
2082                    } catch (Exception e) {
2083                        loge("Failed to reload STA firmware " + e);
2084                        // continue
2085                    }
2086                   try {
2087                       //A runtime crash can leave the interface up and
2088                       //this affects connectivity when supplicant starts up.
2089                       //Ensure interface is down before a supplicant start.
2090                        mNwService.setInterfaceDown(mInterfaceName);
2091                        //Set privacy extensions
2092                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
2093                    } catch (RemoteException re) {
2094                        loge("Unable to change interface settings: " + re);
2095                    } catch (IllegalStateException ie) {
2096                        loge("Unable to change interface settings: " + ie);
2097                    }
2098
2099                    if(mWifiNative.startSupplicant(mP2pSupported)) {
2100                        if (DBG) log("Supplicant start successful");
2101                        mWifiMonitor.startMonitoring();
2102                        transitionTo(mSupplicantStartingState);
2103                    } else {
2104                        loge("Failed to start supplicant!");
2105                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2106                    }
2107                    break;
2108                case CMD_START_AP:
2109                    transitionTo(mSoftApStartingState);
2110                    break;
2111                default:
2112                    return NOT_HANDLED;
2113            }
2114            return HANDLED;
2115        }
2116    }
2117
2118    class DriverUnloadingState extends State {
2119        @Override
2120        public void enter() {
2121            if (DBG) log(getName() + "\n");
2122            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2123
2124            final Message message = new Message();
2125            message.copyFrom(getCurrentMessage());
2126            new Thread(new Runnable() {
2127                public void run() {
2128                    if (DBG) log(getName() + message.toString() + "\n");
2129                    mWakeLock.acquire();
2130                    if(mWifiNative.unloadDriver()) {
2131                        if (DBG) log("Driver unload successful");
2132                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
2133
2134                        switch(message.arg1) {
2135                            case WIFI_STATE_DISABLED:
2136                            case WIFI_STATE_UNKNOWN:
2137                                setWifiState(message.arg1);
2138                                break;
2139                            case WIFI_AP_STATE_DISABLED:
2140                            case WIFI_AP_STATE_FAILED:
2141                                setWifiApState(message.arg1);
2142                                break;
2143                        }
2144                    } else {
2145                        loge("Failed to unload driver!");
2146                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
2147
2148                        switch(message.arg1) {
2149                            case WIFI_STATE_DISABLED:
2150                            case WIFI_STATE_UNKNOWN:
2151                                setWifiState(WIFI_STATE_UNKNOWN);
2152                                break;
2153                            case WIFI_AP_STATE_DISABLED:
2154                            case WIFI_AP_STATE_FAILED:
2155                                setWifiApState(WIFI_AP_STATE_FAILED);
2156                                break;
2157                        }
2158                    }
2159                    mWakeLock.release();
2160                }
2161            }).start();
2162        }
2163
2164        @Override
2165        public boolean processMessage(Message message) {
2166            if (DBG) log(getName() + message.toString() + "\n");
2167            switch (message.what) {
2168                case CMD_UNLOAD_DRIVER_SUCCESS:
2169                    transitionTo(mDriverUnloadedState);
2170                    break;
2171                case CMD_UNLOAD_DRIVER_FAILURE:
2172                    transitionTo(mDriverFailedState);
2173                    break;
2174                case CMD_LOAD_DRIVER:
2175                case CMD_UNLOAD_DRIVER:
2176                case CMD_START_SUPPLICANT:
2177                case CMD_STOP_SUPPLICANT:
2178                case CMD_START_AP:
2179                case CMD_STOP_AP:
2180                case CMD_START_DRIVER:
2181                case CMD_STOP_DRIVER:
2182                case CMD_SET_SCAN_MODE:
2183                case CMD_SET_SCAN_TYPE:
2184                case CMD_SET_COUNTRY_CODE:
2185                case CMD_SET_FREQUENCY_BAND:
2186                case CMD_START_PACKET_FILTERING:
2187                case CMD_STOP_PACKET_FILTERING:
2188                    deferMessage(message);
2189                    break;
2190                default:
2191                    return NOT_HANDLED;
2192            }
2193            return HANDLED;
2194        }
2195    }
2196
2197    class DriverUnloadedState extends State {
2198        @Override
2199        public void enter() {
2200            if (DBG) log(getName() + "\n");
2201            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2202        }
2203        @Override
2204        public boolean processMessage(Message message) {
2205            if (DBG) log(getName() + message.toString() + "\n");
2206            switch (message.what) {
2207                case CMD_LOAD_DRIVER:
2208                    transitionTo(mDriverLoadingState);
2209                    break;
2210                default:
2211                    return NOT_HANDLED;
2212            }
2213            return HANDLED;
2214        }
2215    }
2216
2217    class DriverFailedState extends State {
2218        @Override
2219        public void enter() {
2220            loge(getName() + "\n");
2221            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2222        }
2223        @Override
2224        public boolean processMessage(Message message) {
2225            if (DBG) log(getName() + message.toString() + "\n");
2226            return NOT_HANDLED;
2227        }
2228    }
2229
2230
2231    class SupplicantStartingState extends State {
2232        @Override
2233        public void enter() {
2234            if (DBG) log(getName() + "\n");
2235            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2236        }
2237
2238        private void initializeWpsDetails() {
2239            String detail;
2240            detail = SystemProperties.get("ro.product.name", "");
2241            if (!mWifiNative.setDeviceName(detail)) {
2242                loge("Failed to set device name " +  detail);
2243            }
2244            detail = SystemProperties.get("ro.product.manufacturer", "");
2245            if (!mWifiNative.setManufacturer(detail)) {
2246                loge("Failed to set manufacturer " + detail);
2247            }
2248            detail = SystemProperties.get("ro.product.model", "");
2249            if (!mWifiNative.setModelName(detail)) {
2250                loge("Failed to set model name " + detail);
2251            }
2252            detail = SystemProperties.get("ro.product.model", "");
2253            if (!mWifiNative.setModelNumber(detail)) {
2254                loge("Failed to set model number " + detail);
2255            }
2256            detail = SystemProperties.get("ro.serialno", "");
2257            if (!mWifiNative.setSerialNumber(detail)) {
2258                loge("Failed to set serial number " + detail);
2259            }
2260            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) {
2261                loge("Failed to set WPS config methods");
2262            }
2263            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
2264                loge("Failed to set primary device type " + mPrimaryDeviceType);
2265            }
2266        }
2267
2268        @Override
2269        public boolean processMessage(Message message) {
2270            if (DBG) log(getName() + message.toString() + "\n");
2271            switch(message.what) {
2272                case WifiMonitor.SUP_CONNECTION_EVENT:
2273                    if (DBG) log("Supplicant connection established");
2274                    setWifiState(WIFI_STATE_ENABLED);
2275                    mSupplicantRestartCount = 0;
2276                    /* Reset the supplicant state to indicate the supplicant
2277                     * state is not known at this time */
2278                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2279                    /* Initialize data structures */
2280                    mLastBssid = null;
2281                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2282                    mLastSignalLevel = -1;
2283
2284                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
2285                    mWifiConfigStore.initialize();
2286                    initializeWpsDetails();
2287
2288                    sendSupplicantConnectionChangedBroadcast(true);
2289                    transitionTo(mDriverStartedState);
2290                    break;
2291                case WifiMonitor.SUP_DISCONNECTION_EVENT:
2292                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2293                        loge("Failed to setup control channel, restart supplicant");
2294                        mWifiNative.killSupplicant();
2295                        transitionTo(mDriverLoadedState);
2296                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2297                    } else {
2298                        loge("Failed " + mSupplicantRestartCount +
2299                                " times to start supplicant, unload driver");
2300                        mSupplicantRestartCount = 0;
2301                        transitionTo(mDriverLoadedState);
2302                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2303                    }
2304                    break;
2305                case CMD_LOAD_DRIVER:
2306                case CMD_UNLOAD_DRIVER:
2307                case CMD_START_SUPPLICANT:
2308                case CMD_STOP_SUPPLICANT:
2309                case CMD_START_AP:
2310                case CMD_STOP_AP:
2311                case CMD_START_DRIVER:
2312                case CMD_STOP_DRIVER:
2313                case CMD_SET_SCAN_MODE:
2314                case CMD_SET_SCAN_TYPE:
2315                case CMD_SET_COUNTRY_CODE:
2316                case CMD_SET_FREQUENCY_BAND:
2317                case CMD_START_PACKET_FILTERING:
2318                case CMD_STOP_PACKET_FILTERING:
2319                    deferMessage(message);
2320                    break;
2321                default:
2322                    return NOT_HANDLED;
2323            }
2324            return HANDLED;
2325        }
2326    }
2327
2328    class SupplicantStartedState extends State {
2329        @Override
2330        public void enter() {
2331            if (DBG) log(getName() + "\n");
2332            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2333            /* Initialize for connect mode operation at start */
2334            mIsScanMode = false;
2335            /* Wifi is available as long as we have a connection to supplicant */
2336            mNetworkInfo.setIsAvailable(true);
2337
2338            int defaultInterval = mContext.getResources().getInteger(
2339                    com.android.internal.R.integer.config_wifi_supplicant_scan_interval);
2340
2341            mSupplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2342                    Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2343                    defaultInterval);
2344
2345            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
2346        }
2347        @Override
2348        public boolean processMessage(Message message) {
2349            if (DBG) log(getName() + message.toString() + "\n");
2350            WifiConfiguration config;
2351            switch(message.what) {
2352                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
2353                    transitionTo(mSupplicantStoppingState);
2354                    break;
2355                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
2356                    loge("Connection lost, restart supplicant");
2357                    mWifiNative.killSupplicant();
2358                    mWifiNative.closeSupplicantConnection();
2359                    mNetworkInfo.setIsAvailable(false);
2360                    handleNetworkDisconnect();
2361                    sendSupplicantConnectionChangedBroadcast(false);
2362                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2363                    transitionTo(mDriverLoadedState);
2364                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2365                    break;
2366                case WifiMonitor.SCAN_RESULTS_EVENT:
2367                    setScanResults(mWifiNative.scanResults());
2368                    sendScanResultsAvailableBroadcast();
2369                    mScanResultIsPending = false;
2370                    break;
2371                case CMD_PING_SUPPLICANT:
2372                    boolean ok = mWifiNative.ping();
2373                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2374                    break;
2375                case CMD_ADD_OR_UPDATE_NETWORK:
2376                    config = (WifiConfiguration) message.obj;
2377                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2378                            mWifiConfigStore.addOrUpdateNetwork(config));
2379                    break;
2380                case CMD_REMOVE_NETWORK:
2381                    ok = mWifiConfigStore.removeNetwork(message.arg1);
2382                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2383                    break;
2384                case CMD_ENABLE_NETWORK:
2385                    ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2386                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2387                    break;
2388                case CMD_ENABLE_ALL_NETWORKS:
2389                    long time =  android.os.SystemClock.elapsedRealtime();
2390                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
2391                        mWifiConfigStore.enableAllNetworks();
2392                        mLastEnableAllNetworksTime = time;
2393                    }
2394                    break;
2395                case WifiManager.DISABLE_NETWORK:
2396                    if (mWifiConfigStore.disableNetwork(message.arg1,
2397                            WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
2398                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
2399                    } else {
2400                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
2401                                WifiManager.ERROR);
2402                    }
2403                    break;
2404                case CMD_BLACKLIST_NETWORK:
2405                    mWifiNative.addToBlacklist((String)message.obj);
2406                    break;
2407                case CMD_CLEAR_BLACKLIST:
2408                    mWifiNative.clearBlacklist();
2409                    break;
2410                case CMD_SAVE_CONFIG:
2411                    ok = mWifiConfigStore.saveConfig();
2412                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2413
2414                    // Inform the backup manager about a data change
2415                    IBackupManager ibm = IBackupManager.Stub.asInterface(
2416                            ServiceManager.getService(Context.BACKUP_SERVICE));
2417                    if (ibm != null) {
2418                        try {
2419                            ibm.dataChanged("com.android.providers.settings");
2420                        } catch (Exception e) {
2421                            // Try again later
2422                        }
2423                    }
2424                    break;
2425                case CMD_GET_CONFIGURED_NETWORKS:
2426                    replyToMessage(message, message.what,
2427                            mWifiConfigStore.getConfiguredNetworks());
2428                    break;
2429                    /* Cannot start soft AP while in client mode */
2430                case CMD_START_AP:
2431                    loge("Failed to start soft AP with a running supplicant");
2432                    setWifiApState(WIFI_AP_STATE_FAILED);
2433                    break;
2434                case CMD_SET_SCAN_MODE:
2435                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2436                    break;
2437                case WifiManager.SAVE_NETWORK:
2438                    config = (WifiConfiguration) message.obj;
2439                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2440                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
2441                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
2442                    } else {
2443                        loge("Failed to save network");
2444                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
2445                                WifiManager.ERROR);
2446                    }
2447                    break;
2448                case WifiManager.FORGET_NETWORK:
2449                    if (mWifiConfigStore.forgetNetwork(message.arg1)) {
2450                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
2451                    } else {
2452                        loge("Failed to forget network");
2453                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
2454                                WifiManager.ERROR);
2455                    }
2456                    break;
2457                default:
2458                    return NOT_HANDLED;
2459            }
2460            return HANDLED;
2461        }
2462
2463        @Override
2464        public void exit() {
2465            mNetworkInfo.setIsAvailable(false);
2466        }
2467    }
2468
2469    class SupplicantStoppingState extends State {
2470        @Override
2471        public void enter() {
2472            if (DBG) log(getName() + "\n");
2473            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2474
2475            /* Send any reset commands to supplicant before shutting it down */
2476            handleNetworkDisconnect();
2477
2478            if (DBG) log("stopping supplicant");
2479            if (!mWifiNative.stopSupplicant()) {
2480                loge("Failed to stop supplicant");
2481            }
2482
2483            /* Send ourselves a delayed message to indicate failure after a wait time */
2484            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
2485                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
2486
2487            mNetworkInfo.setIsAvailable(false);
2488            setWifiState(WIFI_STATE_DISABLING);
2489            sendSupplicantConnectionChangedBroadcast(false);
2490            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2491        }
2492        @Override
2493        public boolean processMessage(Message message) {
2494            if (DBG) log(getName() + message.toString() + "\n");
2495            switch(message.what) {
2496                case WifiMonitor.SUP_CONNECTION_EVENT:
2497                    loge("Supplicant connection received while stopping");
2498                    break;
2499                case WifiMonitor.SUP_DISCONNECTION_EVENT:
2500                    if (DBG) log("Supplicant connection lost");
2501                    /* Socket connection can be lost when we do a graceful shutdown
2502                     * or when the driver is hung. Ensure supplicant is stopped here.
2503                     */
2504                    mWifiNative.killSupplicant();
2505                    mWifiNative.closeSupplicantConnection();
2506                    transitionTo(mDriverLoadedState);
2507                    break;
2508                case CMD_STOP_SUPPLICANT_FAILED:
2509                    if (message.arg1 == mSupplicantStopFailureToken) {
2510                        loge("Timed out on a supplicant stop, kill and proceed");
2511                        mWifiNative.killSupplicant();
2512                        mWifiNative.closeSupplicantConnection();
2513                        transitionTo(mDriverLoadedState);
2514                    }
2515                    break;
2516                case CMD_LOAD_DRIVER:
2517                case CMD_UNLOAD_DRIVER:
2518                case CMD_START_SUPPLICANT:
2519                case CMD_STOP_SUPPLICANT:
2520                case CMD_START_AP:
2521                case CMD_STOP_AP:
2522                case CMD_START_DRIVER:
2523                case CMD_STOP_DRIVER:
2524                case CMD_SET_SCAN_MODE:
2525                case CMD_SET_SCAN_TYPE:
2526                case CMD_SET_COUNTRY_CODE:
2527                case CMD_SET_FREQUENCY_BAND:
2528                case CMD_START_PACKET_FILTERING:
2529                case CMD_STOP_PACKET_FILTERING:
2530                    deferMessage(message);
2531                    break;
2532                default:
2533                    return NOT_HANDLED;
2534            }
2535            return HANDLED;
2536        }
2537    }
2538
2539    class DriverStartingState extends State {
2540        private int mTries;
2541        @Override
2542        public void enter() {
2543            if (DBG) log(getName() + "\n");
2544            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2545
2546            mTries = 1;
2547            /* Send ourselves a delayed message to start driver a second time */
2548            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2549                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2550        }
2551        @Override
2552        public boolean processMessage(Message message) {
2553            if (DBG) log(getName() + message.toString() + "\n");
2554            switch(message.what) {
2555               case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2556                    SupplicantState state = handleSupplicantStateChange(message);
2557                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
2558                     * a state that indicates driver has started, it is ready to
2559                     * receive driver commands
2560                     */
2561                    if (SupplicantState.isDriverActive(state)) {
2562                        transitionTo(mDriverStartedState);
2563                    }
2564                    break;
2565                case CMD_DRIVER_START_TIMED_OUT:
2566                    if (message.arg1 == mDriverStartToken) {
2567                        if (mTries >= 2) {
2568                            loge("Failed to start driver after " + mTries);
2569                            transitionTo(mDriverStoppedState);
2570                        } else {
2571                            loge("Driver start failed, retrying");
2572                            mWakeLock.acquire();
2573                            mWifiNative.startDriver();
2574                            mWakeLock.release();
2575
2576                            ++mTries;
2577                            /* Send ourselves a delayed message to start driver again */
2578                            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2579                                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2580                        }
2581                    }
2582                    break;
2583                    /* Queue driver commands & connection events */
2584                case CMD_START_DRIVER:
2585                case CMD_STOP_DRIVER:
2586                case WifiMonitor.NETWORK_CONNECTION_EVENT:
2587                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2588                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2589                case WifiMonitor.WPS_OVERLAP_EVENT:
2590                case CMD_SET_SCAN_TYPE:
2591                case CMD_SET_COUNTRY_CODE:
2592                case CMD_SET_FREQUENCY_BAND:
2593                case CMD_START_PACKET_FILTERING:
2594                case CMD_STOP_PACKET_FILTERING:
2595                case CMD_START_SCAN:
2596                case CMD_DISCONNECT:
2597                case CMD_REASSOCIATE:
2598                case CMD_RECONNECT:
2599                    deferMessage(message);
2600                    break;
2601                default:
2602                    return NOT_HANDLED;
2603            }
2604            return HANDLED;
2605        }
2606    }
2607
2608    class DriverStartedState extends State {
2609        @Override
2610        public void enter() {
2611            if (DBG) log(getName() + "\n");
2612            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2613
2614            mIsRunning = true;
2615            mInDelayedStop = false;
2616            updateBatteryWorkSource(null);
2617
2618            /**
2619             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2620             * When this mode is on, some of the low-level scan parameters used by the
2621             * driver are changed to reduce interference with bluetooth
2622             */
2623            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2624            /* set country code */
2625            setCountryCode();
2626            /* set frequency band of operation */
2627            setFrequencyBand();
2628            /* initialize network state */
2629            setNetworkDetailedState(DetailedState.DISCONNECTED);
2630
2631            /* Remove any filtering on Multicast v6 at start */
2632            mWifiNative.stopFilteringMulticastV6Packets();
2633
2634            /* Reset Multicast v4 filtering state */
2635            if (mFilteringMulticastV4Packets.get()) {
2636                mWifiNative.startFilteringMulticastV4Packets();
2637            } else {
2638                mWifiNative.stopFilteringMulticastV4Packets();
2639            }
2640
2641            mWifiNative.setPowerSave(mPowerSaveEnabled);
2642
2643            if (mIsScanMode) {
2644                mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
2645                mWifiNative.disconnect();
2646                transitionTo(mScanModeState);
2647            } else {
2648                mWifiNative.setScanResultHandling(CONNECT_MODE);
2649                mWifiNative.reconnect();
2650                // Status pulls in the current supplicant state and network connection state
2651                // events over the monitor connection. This helps framework sync up with
2652                // current supplicant state
2653                mWifiNative.status();
2654                transitionTo(mDisconnectedState);
2655            }
2656
2657            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
2658
2659            mContext.registerReceiver(mScreenReceiver, mScreenFilter);
2660        }
2661        @Override
2662        public boolean processMessage(Message message) {
2663            if (DBG) log(getName() + message.toString() + "\n");
2664            switch(message.what) {
2665               case CMD_SET_SCAN_TYPE:
2666                    mSetScanActive = (message.arg1 == SCAN_ACTIVE);
2667                    mWifiNative.setScanMode(mSetScanActive);
2668                    break;
2669                case CMD_START_SCAN:
2670                    boolean forceActive = (message.arg1 == SCAN_ACTIVE);
2671                    if (forceActive && !mSetScanActive) {
2672                        mWifiNative.setScanMode(forceActive);
2673                    }
2674                    mWifiNative.scan();
2675                    if (forceActive && !mSetScanActive) {
2676                        mWifiNative.setScanMode(mSetScanActive);
2677                    }
2678                    mScanResultIsPending = true;
2679                    break;
2680                case CMD_SET_COUNTRY_CODE:
2681                    String country = (String) message.obj;
2682                    if (DBG) log("set country code " + country);
2683                    if (!mWifiNative.setCountryCode(country.toUpperCase())) {
2684                        loge("Failed to set country code " + country);
2685                    }
2686                    break;
2687                case CMD_SET_FREQUENCY_BAND:
2688                    int band =  message.arg1;
2689                    if (DBG) log("set frequency band " + band);
2690                    if (mWifiNative.setBand(band)) {
2691                        mFrequencyBand.set(band);
2692                        //Fetch the latest scan results when frequency band is set
2693                        startScan(true);
2694                    } else {
2695                        loge("Failed to set frequency band " + band);
2696                    }
2697                    break;
2698                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2699                    mBluetoothConnectionActive = (message.arg1 !=
2700                            BluetoothAdapter.STATE_DISCONNECTED);
2701                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2702                    break;
2703                case CMD_STOP_DRIVER:
2704                    int mode = message.arg1;
2705
2706                    /* Already doing a delayed stop && not in ecm state */
2707                    if (mInDelayedStop && mode != IN_ECM_STATE) {
2708                        if (DBG) log("Already in delayed stop");
2709                        break;
2710                    }
2711                    mInDelayedStop = true;
2712                    mDelayedStopCounter++;
2713                    if (DBG) log("Delayed stop message " + mDelayedStopCounter);
2714
2715                    if (mode == IN_ECM_STATE) {
2716                        /* send a shut down immediately */
2717                        sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
2718                    } else {
2719                        /* send regular delayed shut down */
2720                        Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
2721                        driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
2722                        mDriverStopIntent = PendingIntent.getBroadcast(mContext,
2723                                DRIVER_STOP_REQUEST, driverStopIntent,
2724                                PendingIntent.FLAG_UPDATE_CURRENT);
2725
2726                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
2727                                + mDriverStopDelayMs, mDriverStopIntent);
2728                    }
2729                    break;
2730                case CMD_START_DRIVER:
2731                    if (mInDelayedStop) {
2732                        mInDelayedStop = false;
2733                        mDelayedStopCounter++;
2734                        mAlarmManager.cancel(mDriverStopIntent);
2735                        if (DBG) log("Delayed stop ignored due to start");
2736                    }
2737                    break;
2738                case CMD_DELAYED_STOP_DRIVER:
2739                    if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
2740                    if (message.arg1 != mDelayedStopCounter) break;
2741                    if (getCurrentState() != mDisconnectedState) {
2742                        mWifiNative.disconnect();
2743                        handleNetworkDisconnect();
2744                    }
2745                    mWakeLock.acquire();
2746                    mWifiNative.stopDriver();
2747                    transitionTo(mDriverStoppingState);
2748                    mWakeLock.release();
2749                    break;
2750                case CMD_START_PACKET_FILTERING:
2751                    if (message.arg1 == MULTICAST_V6) {
2752                        mWifiNative.startFilteringMulticastV6Packets();
2753                    } else if (message.arg1 == MULTICAST_V4) {
2754                        mWifiNative.startFilteringMulticastV4Packets();
2755                    } else {
2756                        loge("Illegal arugments to CMD_START_PACKET_FILTERING");
2757                    }
2758                    break;
2759                case CMD_STOP_PACKET_FILTERING:
2760                    if (message.arg1 == MULTICAST_V6) {
2761                        mWifiNative.stopFilteringMulticastV6Packets();
2762                    } else if (message.arg1 == MULTICAST_V4) {
2763                        mWifiNative.stopFilteringMulticastV4Packets();
2764                    } else {
2765                        loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
2766                    }
2767                    break;
2768                case CMD_SET_SUSPEND_OPTIMIZATIONS:
2769                    if (!mHighPerfMode) {
2770                        mWifiNative.setSuspendOptimizations(true);
2771                    }
2772                    mSuspendWakeLock.release();
2773                    break;
2774                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
2775                    mWifiNative.setSuspendOptimizations(false);
2776                    break;
2777                case CMD_SET_HIGH_PERF_MODE:
2778                    mHighPerfMode = (message.arg1 == 1);
2779                    if (mHighPerfMode) {
2780                        //Disable any suspend optimizations
2781                        mWifiNative.setSuspendOptimizations(false);
2782                    }
2783                    break;
2784                default:
2785                    return NOT_HANDLED;
2786            }
2787            return HANDLED;
2788        }
2789        @Override
2790        public void exit() {
2791            if (DBG) log(getName() + "\n");
2792            mIsRunning = false;
2793            updateBatteryWorkSource(null);
2794            mScanResults = null;
2795
2796            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
2797            mContext.unregisterReceiver(mScreenReceiver);
2798        }
2799    }
2800
2801    class DriverStoppingState extends State {
2802        @Override
2803        public void enter() {
2804            if (DBG) log(getName() + "\n");
2805            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2806        }
2807        @Override
2808        public boolean processMessage(Message message) {
2809            if (DBG) log(getName() + message.toString() + "\n");
2810            switch(message.what) {
2811                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2812                    SupplicantState state = handleSupplicantStateChange(message);
2813                    if (state == SupplicantState.INTERFACE_DISABLED) {
2814                        transitionTo(mDriverStoppedState);
2815                    }
2816                    break;
2817                    /* Queue driver commands */
2818                case CMD_START_DRIVER:
2819                case CMD_STOP_DRIVER:
2820                case CMD_SET_SCAN_TYPE:
2821                case CMD_SET_COUNTRY_CODE:
2822                case CMD_SET_FREQUENCY_BAND:
2823                case CMD_START_PACKET_FILTERING:
2824                case CMD_STOP_PACKET_FILTERING:
2825                case CMD_START_SCAN:
2826                case CMD_DISCONNECT:
2827                case CMD_REASSOCIATE:
2828                case CMD_RECONNECT:
2829                    deferMessage(message);
2830                    break;
2831                default:
2832                    return NOT_HANDLED;
2833            }
2834            return HANDLED;
2835        }
2836    }
2837
2838    class DriverStoppedState extends State {
2839        @Override
2840        public void enter() {
2841            if (DBG) log(getName() + "\n");
2842            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2843        }
2844        @Override
2845        public boolean processMessage(Message message) {
2846            if (DBG) log(getName() + message.toString() + "\n");
2847            switch (message.what) {
2848                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2849                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2850                    SupplicantState state = stateChangeResult.state;
2851                    // A WEXT bug means that we can be back to driver started state
2852                    // unexpectedly
2853                    if (SupplicantState.isDriverActive(state)) {
2854                        transitionTo(mDriverStartedState);
2855                    }
2856                    break;
2857                case CMD_START_DRIVER:
2858                    mWakeLock.acquire();
2859                    mWifiNative.startDriver();
2860                    mWakeLock.release();
2861                    transitionTo(mDriverStartingState);
2862                    break;
2863                default:
2864                    return NOT_HANDLED;
2865            }
2866            return HANDLED;
2867        }
2868    }
2869
2870    class ScanModeState extends State {
2871        @Override
2872        public void enter() {
2873            if (DBG) log(getName() + "\n");
2874            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2875        }
2876        @Override
2877        public boolean processMessage(Message message) {
2878            if (DBG) log(getName() + message.toString() + "\n");
2879            switch(message.what) {
2880                case CMD_SET_SCAN_MODE:
2881                    if (message.arg1 == SCAN_ONLY_MODE) {
2882                        /* Ignore */
2883                        return HANDLED;
2884                    } else {
2885                        mWifiNative.setScanResultHandling(message.arg1);
2886                        mWifiNative.reconnect();
2887                        mIsScanMode = false;
2888                        transitionTo(mDisconnectedState);
2889                    }
2890                    break;
2891                    /* Ignore */
2892                case CMD_DISCONNECT:
2893                case CMD_RECONNECT:
2894                case CMD_REASSOCIATE:
2895                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2896                case WifiMonitor.NETWORK_CONNECTION_EVENT:
2897                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2898                    break;
2899                default:
2900                    return NOT_HANDLED;
2901            }
2902            return HANDLED;
2903        }
2904    }
2905
2906    class ConnectModeState extends State {
2907        @Override
2908        public void enter() {
2909            if (DBG) log(getName() + "\n");
2910            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2911        }
2912        @Override
2913        public boolean processMessage(Message message) {
2914            if (DBG) log(getName() + message.toString() + "\n");
2915            StateChangeResult stateChangeResult;
2916            switch(message.what) {
2917                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2918                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
2919                    break;
2920                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2921                    SupplicantState state = handleSupplicantStateChange(message);
2922                    // A driver/firmware hang can now put the interface in a down state.
2923                    // We detect the interface going down and recover from it
2924                    if (!SupplicantState.isDriverActive(state)) {
2925                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2926                            handleNetworkDisconnect();
2927                        }
2928                        log("Detected an interface down, restart driver");
2929                        transitionTo(mDriverStoppedState);
2930                        sendMessage(CMD_START_DRIVER);
2931                        break;
2932                    }
2933
2934                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
2935                    // when authentication times out after a successful connection,
2936                    // we can figure this from the supplicant state. If supplicant
2937                    // state is DISCONNECTED, but the mNetworkInfo says we are not
2938                    // disconnected, we need to handle a disconnection
2939                    if (state == SupplicantState.DISCONNECTED &&
2940                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2941                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
2942                        handleNetworkDisconnect();
2943                        transitionTo(mDisconnectedState);
2944                    }
2945                    break;
2946                    /* Do a redundant disconnect without transition */
2947                case CMD_DISCONNECT:
2948                    mWifiNative.disconnect();
2949                    break;
2950                case CMD_RECONNECT:
2951                    mWifiNative.reconnect();
2952                    break;
2953                case CMD_REASSOCIATE:
2954                    mWifiNative.reassociate();
2955                    break;
2956                case WifiManager.CONNECT_NETWORK:
2957                    /* The connect message can contain a network id passed as arg1 on message or
2958                     * or a config passed as obj on message.
2959                     * For a new network, a config is passed to create and connect.
2960                     * For an existing network, a network id is passed
2961                     */
2962                    int netId = message.arg1;
2963                    WifiConfiguration config = (WifiConfiguration) message.obj;
2964
2965                    /* Save the network config */
2966                    if (config != null) {
2967                        NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2968                        netId = result.getNetworkId();
2969                    }
2970
2971                    if (mWifiConfigStore.selectNetwork(netId) &&
2972                            mWifiNative.reconnect()) {
2973                        /* The state tracker handles enabling networks upon completion/failure */
2974                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
2975                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
2976                        /* Expect a disconnection from the old connection */
2977                        transitionTo(mDisconnectingState);
2978                    } else {
2979                        loge("Failed to connect config: " + config + " netId: " + netId);
2980                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
2981                                WifiManager.ERROR);
2982                        break;
2983                    }
2984                    break;
2985                case WifiManager.START_WPS:
2986                    WpsInfo wpsInfo = (WpsInfo) message.obj;
2987                    WpsResult result;
2988                    switch (wpsInfo.setup) {
2989                        case WpsInfo.PBC:
2990                            result = mWifiConfigStore.startWpsPbc(wpsInfo);
2991                            break;
2992                        case WpsInfo.KEYPAD:
2993                            result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
2994                            break;
2995                        case WpsInfo.DISPLAY:
2996                            result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
2997                            break;
2998                        default:
2999                            result = new WpsResult(Status.FAILURE);
3000                            Log.e(TAG, "Invalid setup for WPS");
3001                            break;
3002                    }
3003                    if (result.status == Status.SUCCESS) {
3004                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result);
3005                        transitionTo(mWpsRunningState);
3006                    } else {
3007                        Log.e(TAG, "Failed to start WPS with config " + wpsInfo.toString());
3008                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
3009                    }
3010                    break;
3011                case WifiMonitor.SCAN_RESULTS_EVENT:
3012                    /* Set the scan setting back to "connect" mode */
3013                    mWifiNative.setScanResultHandling(CONNECT_MODE);
3014                    /* Handle scan results */
3015                    return NOT_HANDLED;
3016                case WifiMonitor.NETWORK_CONNECTION_EVENT:
3017                    if (DBG) log("Network connection established");
3018                    mLastNetworkId = message.arg1;
3019                    mLastBssid = (String) message.obj;
3020
3021                    mWifiInfo.setBSSID(mLastBssid);
3022                    mWifiInfo.setNetworkId(mLastNetworkId);
3023                    /* send event to CM & network change broadcast */
3024                    setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
3025                    sendNetworkStateChangeBroadcast(mLastBssid);
3026                    transitionTo(mObtainingIpState);
3027                    break;
3028                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3029                    if (DBG) log("Network connection lost");
3030                    handleNetworkDisconnect();
3031                    transitionTo(mDisconnectedState);
3032                    break;
3033                default:
3034                    return NOT_HANDLED;
3035            }
3036            return HANDLED;
3037        }
3038    }
3039
3040    class L2ConnectedState extends State {
3041        @Override
3042        public void enter() {
3043            if (DBG) log(getName() + "\n");
3044            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3045            mRssiPollToken++;
3046            if (mEnableRssiPolling) {
3047                sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0));
3048            }
3049        }
3050
3051        @Override
3052        public boolean processMessage(Message message) {
3053            if (DBG) log(getName() + message.toString() + "\n");
3054            switch (message.what) {
3055              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
3056                  handlePreDhcpSetup();
3057                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
3058                  break;
3059              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
3060                  handlePostDhcpSetup();
3061                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
3062                      if (DBG) log("DHCP successful");
3063                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
3064                      transitionTo(mVerifyingLinkState);
3065                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
3066                      if (DBG) log("DHCP failed");
3067                      handleFailedIpConfiguration();
3068                      transitionTo(mDisconnectingState);
3069                  }
3070                  break;
3071                case CMD_DISCONNECT:
3072                    mWifiNative.disconnect();
3073                    transitionTo(mDisconnectingState);
3074                    break;
3075                case CMD_SET_SCAN_MODE:
3076                    if (message.arg1 == SCAN_ONLY_MODE) {
3077                        sendMessage(CMD_DISCONNECT);
3078                        deferMessage(message);
3079                    }
3080                    break;
3081                case CMD_START_SCAN:
3082                    /* When the network is connected, re-scanning can trigger
3083                     * a reconnection. Put it in scan-only mode during scan.
3084                     * When scan results are received, the mode is switched
3085                     * back to CONNECT_MODE.
3086                     */
3087                    mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
3088                    /* Have the parent state handle the rest */
3089                    return NOT_HANDLED;
3090                    /* Ignore connection to same network */
3091                case WifiManager.CONNECT_NETWORK:
3092                    int netId = message.arg1;
3093                    if (mWifiInfo.getNetworkId() == netId) {
3094                        break;
3095                    }
3096                    return NOT_HANDLED;
3097                case WifiManager.SAVE_NETWORK:
3098                    WifiConfiguration config = (WifiConfiguration) message.obj;
3099                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3100                    if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
3101                        if (result.hasIpChanged()) {
3102                            log("Reconfiguring IP on connection");
3103                            transitionTo(mObtainingIpState);
3104                        }
3105                        if (result.hasProxyChanged()) {
3106                            log("Reconfiguring proxy on connection");
3107                            configureLinkProperties();
3108                            sendLinkConfigurationChangedBroadcast();
3109                        }
3110                    }
3111
3112                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
3113                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
3114                    } else {
3115                        loge("Failed to save network");
3116                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3117                                WifiManager.ERROR);
3118                    }
3119                    break;
3120                    /* Ignore */
3121                case WifiMonitor.NETWORK_CONNECTION_EVENT:
3122                    break;
3123                case CMD_RSSI_POLL:
3124                    if (message.arg1 == mRssiPollToken) {
3125                        // Get Info and continue polling
3126                        fetchRssiAndLinkSpeedNative();
3127                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3128                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3129                    } else {
3130                        // Polling has completed
3131                    }
3132                    break;
3133                case CMD_ENABLE_RSSI_POLL:
3134                    mEnableRssiPolling = (message.arg1 == 1);
3135                    mRssiPollToken++;
3136                    if (mEnableRssiPolling) {
3137                        // first poll
3138                        fetchRssiAndLinkSpeedNative();
3139                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3140                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3141                    }
3142                    break;
3143                case WifiWatchdogStateMachine.RSSI_FETCH:
3144                    fetchRssiAndLinkSpeedNative();
3145                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_FETCH_SUCCEEDED,
3146                            mWifiInfo.getRssi());
3147                    break;
3148                default:
3149                    return NOT_HANDLED;
3150            }
3151
3152            return HANDLED;
3153        }
3154
3155        @Override
3156        public void exit() {
3157            /* If a scan result is pending in connected state, the supplicant
3158             * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
3159             */
3160            if (mScanResultIsPending) {
3161                mWifiNative.setScanResultHandling(CONNECT_MODE);
3162            }
3163        }
3164    }
3165
3166    class ObtainingIpState extends State {
3167        @Override
3168        public void enter() {
3169            if (DBG) log(getName() + "\n");
3170            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3171
3172            if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
3173                //start DHCP
3174                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
3175                        mContext, WifiStateMachine.this, mInterfaceName);
3176                mDhcpStateMachine.registerForPreDhcpNotification();
3177                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
3178            } else {
3179                DhcpInfoInternal dhcpInfoInternal = mWifiConfigStore.getIpConfiguration(
3180                        mLastNetworkId);
3181                InterfaceConfiguration ifcg = new InterfaceConfiguration();
3182                ifcg.setLinkAddress(dhcpInfoInternal.makeLinkAddress());
3183                ifcg.setInterfaceUp();
3184                try {
3185                    mNwService.setInterfaceConfig(mInterfaceName, ifcg);
3186                    if (DBG) log("Static IP configuration succeeded");
3187                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
3188                } catch (RemoteException re) {
3189                    loge("Static IP configuration failed: " + re);
3190                    sendMessage(CMD_STATIC_IP_FAILURE);
3191                } catch (IllegalStateException e) {
3192                    loge("Static IP configuration failed: " + e);
3193                    sendMessage(CMD_STATIC_IP_FAILURE);
3194                }
3195            }
3196        }
3197      @Override
3198      public boolean processMessage(Message message) {
3199          if (DBG) log(getName() + message.toString() + "\n");
3200          switch(message.what) {
3201            case CMD_STATIC_IP_SUCCESS:
3202                  handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
3203                  transitionTo(mVerifyingLinkState);
3204                  break;
3205              case CMD_STATIC_IP_FAILURE:
3206                  handleFailedIpConfiguration();
3207                  transitionTo(mDisconnectingState);
3208                  break;
3209             case WifiManager.SAVE_NETWORK:
3210                  deferMessage(message);
3211                  break;
3212                  /* Defer any power mode changes since we must keep active power mode at DHCP */
3213              case CMD_SET_HIGH_PERF_MODE:
3214                  deferMessage(message);
3215                  break;
3216              default:
3217                  return NOT_HANDLED;
3218          }
3219          return HANDLED;
3220      }
3221    }
3222
3223    class VerifyingLinkState extends State {
3224        @Override
3225        public void enter() {
3226            if (DBG) log(getName() + "\n");
3227            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3228            setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
3229            mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
3230            sendNetworkStateChangeBroadcast(mLastBssid);
3231        }
3232        @Override
3233        public boolean processMessage(Message message) {
3234            switch (message.what) {
3235                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3236                    //stay here
3237                    break;
3238                case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
3239                    try {
3240                        mNwService.enableIpv6(mInterfaceName);
3241                    } catch (RemoteException re) {
3242                        loge("Failed to enable IPv6: " + re);
3243                    } catch (IllegalStateException e) {
3244                        loge("Failed to enable IPv6: " + e);
3245                    }
3246
3247                    setNetworkDetailedState(DetailedState.CONNECTED);
3248                    mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
3249                    sendNetworkStateChangeBroadcast(mLastBssid);
3250                    transitionTo(mConnectedState);
3251                    break;
3252                default:
3253                    return NOT_HANDLED;
3254            }
3255            return HANDLED;
3256        }
3257    }
3258
3259    class ConnectedState extends State {
3260        @Override
3261        public void enter() {
3262            if (DBG) log(getName() + "\n");
3263            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3264       }
3265        @Override
3266        public boolean processMessage(Message message) {
3267            if (DBG) log(getName() + message.toString() + "\n");
3268            switch (message.what) {
3269               case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3270                    if (DBG) log("Watchdog reports poor link");
3271                    try {
3272                        mNwService.disableIpv6(mInterfaceName);
3273                    } catch (RemoteException re) {
3274                        loge("Failed to disable IPv6: " + re);
3275                    } catch (IllegalStateException e) {
3276                        loge("Failed to disable IPv6: " + e);
3277                    }
3278                    /* Report a disconnect */
3279                    setNetworkDetailedState(DetailedState.DISCONNECTED);
3280                    mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
3281                    sendNetworkStateChangeBroadcast(mLastBssid);
3282
3283                    transitionTo(mVerifyingLinkState);
3284                    break;
3285                default:
3286                    return NOT_HANDLED;
3287            }
3288            return HANDLED;
3289        }
3290        @Override
3291        public void exit() {
3292            /* Request a CS wakelock during transition to mobile */
3293            checkAndSetConnectivityInstance();
3294            mCm.requestNetworkTransitionWakelock(TAG);
3295        }
3296    }
3297
3298    class DisconnectingState extends State {
3299        @Override
3300        public void enter() {
3301            if (DBG) log(getName() + "\n");
3302            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3303        }
3304        @Override
3305        public boolean processMessage(Message message) {
3306            if (DBG) log(getName() + message.toString() + "\n");
3307            switch (message.what) {
3308                case CMD_SET_SCAN_MODE:
3309                    if (message.arg1 == SCAN_ONLY_MODE) {
3310                        deferMessage(message);
3311                    }
3312                    break;
3313                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3314                    /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
3315                     * we have missed the network disconnection, transition to mDisconnectedState
3316                     * and handle the rest of the events there
3317                     */
3318                    deferMessage(message);
3319                    handleNetworkDisconnect();
3320                    transitionTo(mDisconnectedState);
3321                    break;
3322                default:
3323                    return NOT_HANDLED;
3324            }
3325            return HANDLED;
3326        }
3327    }
3328
3329    class DisconnectedState extends State {
3330        private boolean mAlarmEnabled = false;
3331        /* This is set from the overlay config file or from a secure setting.
3332         * A value of 0 disables scanning in the framework.
3333         */
3334        private long mFrameworkScanIntervalMs;
3335
3336        private void setScanAlarm(boolean enabled) {
3337            if (enabled == mAlarmEnabled) return;
3338            if (enabled) {
3339                if (mFrameworkScanIntervalMs > 0) {
3340                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
3341                            System.currentTimeMillis() + mFrameworkScanIntervalMs,
3342                            mFrameworkScanIntervalMs,
3343                            mScanIntent);
3344                    mAlarmEnabled = true;
3345                }
3346            } else {
3347                mAlarmManager.cancel(mScanIntent);
3348                mAlarmEnabled = false;
3349            }
3350        }
3351
3352        @Override
3353        public void enter() {
3354            if (DBG) log(getName() + "\n");
3355            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3356
3357            mFrameworkScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
3358                    Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
3359                    mDefaultFrameworkScanIntervalMs);
3360            /*
3361             * We initiate background scanning if it is enabled, otherwise we
3362             * initiate an infrequent scan that wakes up the device to ensure
3363             * a user connects to an access point on the move
3364             */
3365            if (mEnableBackgroundScan) {
3366                /* If a regular scan result is pending, do not initiate background
3367                 * scan until the scan results are returned. This is needed because
3368                 * initiating a background scan will cancel the regular scan and
3369                 * scan results will not be returned until background scanning is
3370                 * cleared
3371                 */
3372                if (!mScanResultIsPending) {
3373                    mWifiNative.enableBackgroundScan(true);
3374                }
3375            } else {
3376                setScanAlarm(true);
3377            }
3378
3379            /**
3380             * If we have no networks saved, the supplicant stops doing the periodic scan.
3381             * The scans are useful to notify the user of the presence of an open network.
3382             * Note that these are not wake up scans.
3383             */
3384            if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3385                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3386                            ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3387            }
3388        }
3389        @Override
3390        public boolean processMessage(Message message) {
3391            if (DBG) log(getName() + message.toString() + "\n");
3392            boolean ret = HANDLED;
3393            switch (message.what) {
3394                case CMD_NO_NETWORKS_PERIODIC_SCAN:
3395                    if (message.arg1 == mPeriodicScanToken &&
3396                            mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3397                        sendMessage(CMD_START_SCAN);
3398                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3399                                    ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3400                    }
3401                    break;
3402                case WifiManager.FORGET_NETWORK:
3403                case CMD_REMOVE_NETWORK:
3404                    // Set up a delayed message here. After the forget/remove is handled
3405                    // the handled delayed message will determine if there is a need to
3406                    // scan and continue
3407                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3408                                ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3409                    ret = NOT_HANDLED;
3410                    break;
3411                case CMD_SET_SCAN_MODE:
3412                    if (message.arg1 == SCAN_ONLY_MODE) {
3413                        mWifiNative.setScanResultHandling(message.arg1);
3414                        //Supplicant disconnect to prevent further connects
3415                        mWifiNative.disconnect();
3416                        mIsScanMode = true;
3417                        transitionTo(mScanModeState);
3418                    }
3419                    break;
3420                case CMD_ENABLE_BACKGROUND_SCAN:
3421                    mEnableBackgroundScan = (message.arg1 == 1);
3422                    if (mEnableBackgroundScan) {
3423                        mWifiNative.enableBackgroundScan(true);
3424                        setScanAlarm(false);
3425                    } else {
3426                        mWifiNative.enableBackgroundScan(false);
3427                        setScanAlarm(true);
3428                    }
3429                    break;
3430                    /* Ignore network disconnect */
3431                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3432                    break;
3433                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3434                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3435                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
3436                    /* ConnectModeState does the rest of the handling */
3437                    ret = NOT_HANDLED;
3438                    break;
3439                case CMD_START_SCAN:
3440                    /* Disable background scan temporarily during a regular scan */
3441                    if (mEnableBackgroundScan) {
3442                        mWifiNative.enableBackgroundScan(false);
3443                    }
3444                    /* Handled in parent state */
3445                    ret = NOT_HANDLED;
3446                    break;
3447                case WifiMonitor.SCAN_RESULTS_EVENT:
3448                    /* Re-enable background scan when a pending scan result is received */
3449                    if (mEnableBackgroundScan && mScanResultIsPending) {
3450                        mWifiNative.enableBackgroundScan(true);
3451                    }
3452                    /* Handled in parent state */
3453                    ret = NOT_HANDLED;
3454                    break;
3455                default:
3456                    ret = NOT_HANDLED;
3457            }
3458            return ret;
3459        }
3460
3461        @Override
3462        public void exit() {
3463            /* No need for a background scan upon exit from a disconnected state */
3464            if (mEnableBackgroundScan) {
3465                mWifiNative.enableBackgroundScan(false);
3466            }
3467            setScanAlarm(false);
3468        }
3469    }
3470
3471    class WpsRunningState extends State {
3472        //Tracks the source to provide a reply
3473        private Message mSourceMessage;
3474        @Override
3475        public void enter() {
3476            if (DBG) log(getName() + "\n");
3477            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3478            mSourceMessage = Message.obtain(getCurrentMessage());
3479        }
3480        @Override
3481        public boolean processMessage(Message message) {
3482            if (DBG) log(getName() + message.toString() + "\n");
3483            switch (message.what) {
3484                case WifiMonitor.WPS_SUCCESS_EVENT:
3485                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
3486                    mSourceMessage.recycle();
3487                    mSourceMessage = null;
3488                    transitionTo(mDisconnectedState);
3489                    break;
3490                case WifiMonitor.WPS_OVERLAP_EVENT:
3491                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3492                            WifiManager.WPS_OVERLAP_ERROR);
3493                    mSourceMessage.recycle();
3494                    mSourceMessage = null;
3495                    transitionTo(mDisconnectedState);
3496                    break;
3497                case WifiMonitor.WPS_FAIL_EVENT:
3498                    //arg1 has the reason for the failure
3499                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
3500                    mSourceMessage.recycle();
3501                    mSourceMessage = null;
3502                    transitionTo(mDisconnectedState);
3503                    break;
3504                case WifiMonitor.WPS_TIMEOUT_EVENT:
3505                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3506                            WifiManager.WPS_TIMED_OUT);
3507                    mSourceMessage.recycle();
3508                    mSourceMessage = null;
3509                    transitionTo(mDisconnectedState);
3510                    break;
3511                case WifiManager.START_WPS:
3512                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
3513                    break;
3514                case WifiManager.CANCEL_WPS:
3515                    if (mWifiNative.cancelWps()) {
3516                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
3517                    } else {
3518                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
3519                    }
3520                    transitionTo(mDisconnectedState);
3521                    break;
3522                /* Defer all commands that can cause connections to a different network
3523                 * or put the state machine out of connect mode
3524                 */
3525                case CMD_STOP_DRIVER:
3526                case CMD_SET_SCAN_MODE:
3527                case WifiManager.CONNECT_NETWORK:
3528                case CMD_ENABLE_NETWORK:
3529                case CMD_RECONNECT:
3530                case CMD_REASSOCIATE:
3531                case WifiMonitor.NETWORK_CONNECTION_EVENT: /* Handled after exiting WPS state */
3532                    deferMessage(message);
3533                    break;
3534                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3535                    if (DBG) log("Network connection lost");
3536                    handleNetworkDisconnect();
3537                    break;
3538                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3539                    //Throw away supplicant state changes when WPS is running.
3540                    //We will start getting supplicant state changes once we get
3541                    //a WPS success or failure
3542                    break;
3543                default:
3544                    return NOT_HANDLED;
3545            }
3546            return HANDLED;
3547        }
3548
3549        @Override
3550        public void exit() {
3551            mWifiConfigStore.enableAllNetworks();
3552            mWifiConfigStore.loadConfiguredNetworks();
3553        }
3554    }
3555
3556    class SoftApStartingState extends State {
3557        @Override
3558        public void enter() {
3559            if (DBG) log(getName() + "\n");
3560            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3561
3562            final Message message = getCurrentMessage();
3563            if (message.what == CMD_START_AP) {
3564                final WifiConfiguration config = (WifiConfiguration) message.obj;
3565
3566                if (config == null) {
3567                    mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
3568                } else {
3569                    mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
3570                    startSoftApWithConfig(config);
3571                }
3572            } else {
3573                throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
3574            }
3575        }
3576        @Override
3577        public boolean processMessage(Message message) {
3578            if (DBG) log(getName() + message.toString() + "\n");
3579            switch(message.what) {
3580                case CMD_LOAD_DRIVER:
3581                case CMD_UNLOAD_DRIVER:
3582                case CMD_START_SUPPLICANT:
3583                case CMD_STOP_SUPPLICANT:
3584                case CMD_START_AP:
3585                case CMD_STOP_AP:
3586                case CMD_START_DRIVER:
3587                case CMD_STOP_DRIVER:
3588                case CMD_SET_SCAN_MODE:
3589                case CMD_SET_SCAN_TYPE:
3590                case CMD_SET_COUNTRY_CODE:
3591                case CMD_SET_FREQUENCY_BAND:
3592                case CMD_START_PACKET_FILTERING:
3593                case CMD_STOP_PACKET_FILTERING:
3594                case CMD_TETHER_STATE_CHANGE:
3595                    deferMessage(message);
3596                    break;
3597                case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
3598                    WifiConfiguration config = (WifiConfiguration) message.obj;
3599                    if (config != null) {
3600                        startSoftApWithConfig(config);
3601                    } else {
3602                        loge("Softap config is null!");
3603                        sendMessage(CMD_START_AP_FAILURE);
3604                    }
3605                    break;
3606                case CMD_START_AP_SUCCESS:
3607                    setWifiApState(WIFI_AP_STATE_ENABLED);
3608                    transitionTo(mSoftApStartedState);
3609                    break;
3610                case CMD_START_AP_FAILURE:
3611                    // initiate driver unload
3612                    sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
3613                    break;
3614                default:
3615                    return NOT_HANDLED;
3616            }
3617            return HANDLED;
3618        }
3619    }
3620
3621    class SoftApStartedState extends State {
3622        @Override
3623        public void enter() {
3624            if (DBG) log(getName() + "\n");
3625            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3626        }
3627        @Override
3628        public boolean processMessage(Message message) {
3629            if (DBG) log(getName() + message.toString() + "\n");
3630            switch(message.what) {
3631                case CMD_STOP_AP:
3632                    if (DBG) log("Stopping Soft AP");
3633                    setWifiApState(WIFI_AP_STATE_DISABLING);
3634
3635                    /* We have not tethered at this point, so we just shutdown soft Ap */
3636                    try {
3637                        mNwService.stopAccessPoint(mInterfaceName);
3638                    } catch(Exception e) {
3639                        loge("Exception in stopAccessPoint()");
3640                    }
3641                    transitionTo(mDriverLoadedState);
3642                    break;
3643                case CMD_START_AP:
3644                    // Ignore a start on a running access point
3645                    break;
3646                    /* Fail client mode operation when soft AP is enabled */
3647                case CMD_START_SUPPLICANT:
3648                   loge("Cannot start supplicant with a running soft AP");
3649                    setWifiState(WIFI_STATE_UNKNOWN);
3650                    break;
3651                case CMD_TETHER_STATE_CHANGE:
3652                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3653                    if (startTethering(stateChange.available)) {
3654                        transitionTo(mTetheringState);
3655                    }
3656                    break;
3657                default:
3658                    return NOT_HANDLED;
3659            }
3660            return HANDLED;
3661        }
3662    }
3663
3664    class TetheringState extends State {
3665        @Override
3666        public void enter() {
3667            if (DBG) log(getName() + "\n");
3668            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3669
3670            /* Send ourselves a delayed message to shut down if tethering fails to notify */
3671            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3672                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3673        }
3674        @Override
3675        public boolean processMessage(Message message) {
3676            if (DBG) log(getName() + message.toString() + "\n");
3677            switch(message.what) {
3678                case CMD_TETHER_STATE_CHANGE:
3679                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3680                    if (isWifiTethered(stateChange.active)) {
3681                        transitionTo(mTetheredState);
3682                    }
3683                    return HANDLED;
3684                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3685                    if (message.arg1 == mTetherToken) {
3686                        loge("Failed to get tether update, shutdown soft access point");
3687                        setWifiApEnabled(null, false);
3688                    }
3689                    break;
3690                case CMD_LOAD_DRIVER:
3691                case CMD_UNLOAD_DRIVER:
3692                case CMD_START_SUPPLICANT:
3693                case CMD_STOP_SUPPLICANT:
3694                case CMD_START_AP:
3695                case CMD_STOP_AP:
3696                case CMD_START_DRIVER:
3697                case CMD_STOP_DRIVER:
3698                case CMD_SET_SCAN_MODE:
3699                case CMD_SET_SCAN_TYPE:
3700                case CMD_SET_COUNTRY_CODE:
3701                case CMD_SET_FREQUENCY_BAND:
3702                case CMD_START_PACKET_FILTERING:
3703                case CMD_STOP_PACKET_FILTERING:
3704                    deferMessage(message);
3705                    break;
3706                default:
3707                    return NOT_HANDLED;
3708            }
3709            return HANDLED;
3710        }
3711    }
3712
3713    class TetheredState extends State {
3714        @Override
3715        public void enter() {
3716            if (DBG) log(getName() + "\n");
3717            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3718        }
3719        @Override
3720        public boolean processMessage(Message message) {
3721            if (DBG) log(getName() + message.toString() + "\n");
3722            switch(message.what) {
3723                case CMD_TETHER_STATE_CHANGE:
3724                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3725                    if (!isWifiTethered(stateChange.active)) {
3726                        loge("Tethering reports wifi as untethered!, shut down soft Ap");
3727                        setWifiApEnabled(null, false);
3728                    }
3729                    return HANDLED;
3730                case CMD_STOP_AP:
3731                    if (DBG) log("Untethering before stopping AP");
3732                    setWifiApState(WIFI_AP_STATE_DISABLING);
3733                    stopTethering();
3734                    transitionTo(mSoftApStoppingState);
3735                    break;
3736                default:
3737                    return NOT_HANDLED;
3738            }
3739            return HANDLED;
3740        }
3741    }
3742
3743    class SoftApStoppingState extends State {
3744        @Override
3745        public void enter() {
3746            if (DBG) log(getName() + "\n");
3747            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3748
3749            /* Send ourselves a delayed message to shut down if tethering fails to notify */
3750            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3751                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3752
3753        }
3754        @Override
3755        public boolean processMessage(Message message) {
3756            if (DBG) log(getName() + message.toString() + "\n");
3757            switch(message.what) {
3758                case CMD_TETHER_STATE_CHANGE:
3759                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3760
3761                    /* Wait till wifi is untethered */
3762                    if (isWifiTethered(stateChange.active)) break;
3763
3764                    try {
3765                        mNwService.stopAccessPoint(mInterfaceName);
3766                    } catch(Exception e) {
3767                        loge("Exception in stopAccessPoint()");
3768                    }
3769                    transitionTo(mDriverLoadedState);
3770                    break;
3771                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3772                    if (message.arg1 == mTetherToken) {
3773                        loge("Failed to get tether update, force stop access point");
3774                        try {
3775                            mNwService.stopAccessPoint(mInterfaceName);
3776                        } catch(Exception e) {
3777                            loge("Exception in stopAccessPoint()");
3778                        }
3779                        transitionTo(mDriverLoadedState);
3780                    }
3781                    break;
3782                case CMD_LOAD_DRIVER:
3783                case CMD_UNLOAD_DRIVER:
3784                case CMD_START_SUPPLICANT:
3785                case CMD_STOP_SUPPLICANT:
3786                case CMD_START_AP:
3787                case CMD_STOP_AP:
3788                case CMD_START_DRIVER:
3789                case CMD_STOP_DRIVER:
3790                case CMD_SET_SCAN_MODE:
3791                case CMD_SET_SCAN_TYPE:
3792                case CMD_SET_COUNTRY_CODE:
3793                case CMD_SET_FREQUENCY_BAND:
3794                case CMD_START_PACKET_FILTERING:
3795                case CMD_STOP_PACKET_FILTERING:
3796                    deferMessage(message);
3797                    break;
3798                default:
3799                    return NOT_HANDLED;
3800            }
3801            return HANDLED;
3802        }
3803    }
3804
3805    //State machine initiated requests can have replyTo set to null indicating
3806    //there are no recepients, we ignore those reply actions
3807    private void replyToMessage(Message msg, int what) {
3808        if (msg.replyTo == null) return;
3809        Message dstMsg = obtainMessageWithArg2(msg);
3810        dstMsg.what = what;
3811        mReplyChannel.replyToMessage(msg, dstMsg);
3812    }
3813
3814    private void replyToMessage(Message msg, int what, int arg1) {
3815        if (msg.replyTo == null) return;
3816        Message dstMsg = obtainMessageWithArg2(msg);
3817        dstMsg.what = what;
3818        dstMsg.arg1 = arg1;
3819        mReplyChannel.replyToMessage(msg, dstMsg);
3820    }
3821
3822    private void replyToMessage(Message msg, int what, Object obj) {
3823        if (msg.replyTo == null) return;
3824        Message dstMsg = obtainMessageWithArg2(msg);
3825        dstMsg.what = what;
3826        dstMsg.obj = obj;
3827        mReplyChannel.replyToMessage(msg, dstMsg);
3828    }
3829
3830    /**
3831     * arg2 on the source message has a unique id that needs to be retained in replies
3832     * to match the request
3833     *
3834     * see WifiManager for details
3835     */
3836    private Message obtainMessageWithArg2(Message srcMsg) {
3837        Message msg = Message.obtain();
3838        msg.arg2 = srcMsg.arg2;
3839        return msg;
3840    }
3841
3842    private void log(String s) {
3843        Log.d(TAG, s);
3844    }
3845
3846    private void loge(String s) {
3847        Log.e(TAG, s);
3848    }
3849}
3850