OSDN Git Service

Merge "No need to have BASE_DATA_CONNECTION_TRACKER start at 50000." into honeycomb-LTE
[android-x86/frameworks-base.git] / wifi / java / android / net / wifi / WifiStateMachine.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.net.wifi;
18
19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
24
25 /**
26  * TODO: Add soft AP states as part of WIFI_STATE_XXX
27  * Retain WIFI_STATE_ENABLING that indicates driver is loading
28  * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
29  * and WIFI_STATE_FAILED for failure
30  * Deprecate WIFI_STATE_UNKNOWN
31  *
32  * Doing this will simplify the logic for sending broadcasts
33  */
34 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
35 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
36 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
37 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
38 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
39
40 import android.app.AlarmManager;
41 import android.app.PendingIntent;
42 import android.app.backup.IBackupManager;
43 import android.bluetooth.BluetoothAdapter;
44 import android.content.BroadcastReceiver;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.IntentFilter;
48 import android.net.ConnectivityManager;
49 import android.net.DhcpInfo;
50 import android.net.DhcpInfoInternal;
51 import android.net.DhcpStateMachine;
52 import android.net.InterfaceConfiguration;
53 import android.net.LinkAddress;
54 import android.net.LinkProperties;
55 import android.net.NetworkInfo;
56 import android.net.NetworkInfo.DetailedState;
57 import android.net.NetworkUtils;
58 import android.net.wifi.WpsResult.Status;
59 import android.os.Binder;
60 import android.os.IBinder;
61 import android.os.INetworkManagementService;
62 import android.os.Message;
63 import android.os.Messenger;
64 import android.os.PowerManager;
65 import android.os.Process;
66 import android.os.RemoteException;
67 import android.os.ServiceManager;
68 import android.os.SystemProperties;
69 import android.os.WorkSource;
70 import android.provider.Settings;
71 import android.util.EventLog;
72 import android.util.Log;
73 import android.util.LruCache;
74
75 import com.android.internal.app.IBatteryStats;
76 import com.android.internal.util.AsyncChannel;
77 import com.android.internal.util.Protocol;
78 import com.android.internal.util.State;
79 import com.android.internal.util.StateMachine;
80
81 import java.net.InetAddress;
82 import java.util.ArrayList;
83 import java.util.List;
84 import java.util.concurrent.atomic.AtomicInteger;
85 import java.util.regex.Pattern;
86
87 /**
88  * Track the state of Wifi connectivity. All event handling is done here,
89  * and all changes in connectivity state are initiated here.
90  *
91  * @hide
92  */
93 public class WifiStateMachine extends StateMachine {
94
95     private static final String TAG = "WifiStateMachine";
96     private static final String NETWORKTYPE = "WIFI";
97     private static final boolean DBG = false;
98
99     /* TODO: fetch a configurable interface */
100     private static final String SOFTAP_IFACE = "wl0.1";
101
102     private WifiMonitor mWifiMonitor;
103     private INetworkManagementService nwService;
104     private ConnectivityManager mCm;
105
106     /* Scan results handling */
107     private List<ScanResult> mScanResults;
108     private static final Pattern scanResultPattern = Pattern.compile("\t+");
109     private static final int SCAN_RESULT_CACHE_SIZE = 80;
110     private final LruCache<String, ScanResult> mScanResultCache;
111
112     private String mInterfaceName;
113
114     private int mLastSignalLevel = -1;
115     private String mLastBssid;
116     private int mLastNetworkId;
117     private boolean mEnableRssiPolling = false;
118     private boolean mEnableBackgroundScan = false;
119     private int mRssiPollToken = 0;
120     private int mReconnectCount = 0;
121     private boolean mIsScanMode = false;
122     private boolean mScanResultIsPending = false;
123
124     private boolean mBluetoothConnectionActive = false;
125
126     /**
127      * Interval in milliseconds between polling for RSSI
128      * and linkspeed information
129      */
130     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
131
132     /**
133      * Delay between supplicant restarts upon failure to establish connection
134      */
135     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
136
137     /**
138      * Number of times we attempt to restart supplicant
139      */
140     private static final int SUPPLICANT_RESTART_TRIES = 5;
141
142     private int mSupplicantRestartCount = 0;
143
144     private LinkProperties mLinkProperties;
145
146     // Wakelock held during wifi start/stop and driver load/unload
147     private PowerManager.WakeLock mWakeLock;
148
149     private Context mContext;
150
151     private DhcpInfoInternal mDhcpInfoInternal;
152     private WifiInfo mWifiInfo;
153     private NetworkInfo mNetworkInfo;
154     private SupplicantStateTracker mSupplicantStateTracker;
155     private WpsStateMachine mWpsStateMachine;
156     private DhcpStateMachine mDhcpStateMachine;
157
158     private AlarmManager mAlarmManager;
159     private PendingIntent mScanIntent;
160     /* Tracks current frequency mode */
161     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
162
163     // Channel for sending replies.
164     private AsyncChannel mReplyChannel = new AsyncChannel();
165
166     // Event log tags (must be in sync with event-log-tags)
167     private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
168     private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
169     private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
170
171     /* The base for wifi message types */
172     static final int BASE = Protocol.BASE_WIFI;
173     /* Load the driver */
174     static final int CMD_LOAD_DRIVER                      = BASE + 1;
175     /* Unload the driver */
176     static final int CMD_UNLOAD_DRIVER                    = BASE + 2;
177     /* Indicates driver load succeeded */
178     static final int CMD_LOAD_DRIVER_SUCCESS              = BASE + 3;
179     /* Indicates driver load failed */
180     static final int CMD_LOAD_DRIVER_FAILURE              = BASE + 4;
181     /* Indicates driver unload succeeded */
182     static final int CMD_UNLOAD_DRIVER_SUCCESS            = BASE + 5;
183     /* Indicates driver unload failed */
184     static final int CMD_UNLOAD_DRIVER_FAILURE            = BASE + 6;
185
186     /* Start the supplicant */
187     static final int CMD_START_SUPPLICANT                 = BASE + 11;
188     /* Stop the supplicant */
189     static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
190     /* Start the driver */
191     static final int CMD_START_DRIVER                     = BASE + 13;
192     /* Start the driver */
193     static final int CMD_STOP_DRIVER                      = BASE + 14;
194     /* Indicates Static IP succeded */
195     static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
196     /* Indicates Static IP failed */
197     static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
198
199     /* Start the soft access point */
200     static final int CMD_START_AP                         = BASE + 21;
201     /* Stop the soft access point */
202     static final int CMD_STOP_AP                          = BASE + 22;
203     /* Set the soft access point configuration */
204     static final int CMD_SET_AP_CONFIG                    = BASE + 23;
205     /* Get the soft access point configuration */
206     static final int CMD_GET_AP_CONFIG                    = BASE + 24;
207
208     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 25;
209
210     /* Supplicant events */
211     /* Connection to supplicant established */
212     static final int SUP_CONNECTION_EVENT                 = BASE + 31;
213     /* Connection to supplicant lost */
214     static final int SUP_DISCONNECTION_EVENT              = BASE + 32;
215     /* Driver start completed */
216     static final int DRIVER_START_EVENT                   = BASE + 33;
217     /* Driver stop completed */
218     static final int DRIVER_STOP_EVENT                    = BASE + 34;
219     /* Network connection completed */
220     static final int NETWORK_CONNECTION_EVENT             = BASE + 36;
221     /* Network disconnection completed */
222     static final int NETWORK_DISCONNECTION_EVENT          = BASE + 37;
223     /* Scan results are available */
224     static final int SCAN_RESULTS_EVENT                   = BASE + 38;
225     /* Supplicate state changed */
226     static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 39;
227     /* Password failure and EAP authentication failure */
228     static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 40;
229     /* WPS overlap detected */
230     static final int WPS_OVERLAP_EVENT                    = BASE + 41;
231
232
233     /* Supplicant commands */
234     /* Is supplicant alive ? */
235     static final int CMD_PING_SUPPLICANT                  = BASE + 51;
236     /* Add/update a network configuration */
237     static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
238     /* Delete a network */
239     static final int CMD_REMOVE_NETWORK                   = BASE + 53;
240     /* Enable a network. The device will attempt a connection to the given network. */
241     static final int CMD_ENABLE_NETWORK                   = BASE + 54;
242     /* Enable all networks */
243     static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
244     /* Disable a network. The device does not attempt a connection to the given network. */
245     static final int CMD_DISABLE_NETWORK                  = BASE + 56;
246     /* Blacklist network. De-prioritizes the given BSSID for connection. */
247     static final int CMD_BLACKLIST_NETWORK                = BASE + 57;
248     /* Clear the blacklist network list */
249     static final int CMD_CLEAR_BLACKLIST                  = BASE + 58;
250     /* Save configuration */
251     static final int CMD_SAVE_CONFIG                      = BASE + 59;
252
253     /* Supplicant commands after driver start*/
254     /* Initiate a scan */
255     static final int CMD_START_SCAN                       = BASE + 71;
256     /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
257     static final int CMD_SET_SCAN_MODE                    = BASE + 72;
258     /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
259     static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
260     /* Disconnect from a network */
261     static final int CMD_DISCONNECT                       = BASE + 74;
262     /* Reconnect to a network */
263     static final int CMD_RECONNECT                        = BASE + 75;
264     /* Reassociate to a network */
265     static final int CMD_REASSOCIATE                      = BASE + 76;
266     /* Controls power mode and suspend mode optimizations
267      *
268      * When high perf mode is enabled, power mode is set to
269      * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
270      *
271      * When high perf mode is disabled, power mode is set to
272      * POWER_MODE_AUTO and suspend mode optimizations are enabled
273      *
274      * Suspend mode optimizations include:
275      * - packet filtering
276      * - turn off roaming
277      * - DTIM wake up settings
278      */
279     static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
280     /* Set the country code */
281     static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
282     /* Request connectivity manager wake lock before driver stop */
283     static final int CMD_REQUEST_CM_WAKELOCK              = BASE + 81;
284     /* Enables RSSI poll */
285     static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
286     /* RSSI poll */
287     static final int CMD_RSSI_POLL                        = BASE + 83;
288     /* Set up packet filtering */
289     static final int CMD_START_PACKET_FILTERING           = BASE + 84;
290     /* Clear packet filter */
291     static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
292     /* Connect to a specified network (network id
293      * or WifiConfiguration) This involves increasing
294      * the priority of the network, enabling the network
295      * (while disabling others) and issuing a reconnect.
296      * Note that CMD_RECONNECT just does a reconnect to
297      * an existing network. All the networks get enabled
298      * upon a successful connection or a failure.
299      */
300     static final int CMD_CONNECT_NETWORK                  = BASE + 86;
301     /* Save the specified network. This involves adding
302      * an enabled network (if new) and updating the
303      * config and issuing a save on supplicant config.
304      */
305     static final int CMD_SAVE_NETWORK                     = BASE + 87;
306     /* Delete the specified network. This involves
307      * removing the network and issuing a save on
308      * supplicant config.
309      */
310     static final int CMD_FORGET_NETWORK                   = BASE + 88;
311     /* Start Wi-Fi protected setup */
312     static final int CMD_START_WPS                        = BASE + 89;
313     /* Set the frequency band */
314     static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
315     /* Enable background scan for configured networks */
316     static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
317
318     /* Commands from/to the SupplicantStateTracker */
319     /* Reset the supplicant state tracker */
320     static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
321
322     /* Commands/events reported by WpsStateMachine */
323     /* Indicates the completion of WPS activity */
324     static final int WPS_COMPLETED_EVENT                  = BASE + 121;
325     /* Reset the WPS state machine */
326     static final int CMD_RESET_WPS_STATE                  = BASE + 122;
327
328     private static final int CONNECT_MODE   = 1;
329     private static final int SCAN_ONLY_MODE = 2;
330
331     private static final int SCAN_ACTIVE = 1;
332     private static final int SCAN_PASSIVE = 2;
333
334     private static final int SUCCESS = 1;
335     private static final int FAILURE = -1;
336
337     /**
338      * The maximum number of times we will retry a connection to an access point
339      * for which we have failed in acquiring an IP address from DHCP. A value of
340      * N means that we will make N+1 connection attempts in all.
341      * <p>
342      * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
343      * value if a Settings value is not present.
344      */
345     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
346
347     static final int POWER_MODE_ACTIVE = 1;
348     static final int POWER_MODE_AUTO = 0;
349
350     /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
351     private int mPowerMode = POWER_MODE_AUTO;
352
353     /**
354      * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
355      * Settings.Secure value is not present.
356      */
357     private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */
358
359     private static final int MIN_RSSI = -200;
360     private static final int MAX_RSSI = 256;
361
362     /* Constants to indicate if soft ap is running or stopped */
363     private static final int SOFT_AP_STOPPED = 0;
364     private static final int SOFT_AP_RUNNING = 1;
365
366     /* Default parent state */
367     private State mDefaultState = new DefaultState();
368     /* Temporary initial state */
369     private State mInitialState = new InitialState();
370     /* Unloading the driver */
371     private State mDriverUnloadingState = new DriverUnloadingState();
372     /* Loading the driver */
373     private State mDriverUnloadedState = new DriverUnloadedState();
374     /* Driver load/unload failed */
375     private State mDriverFailedState = new DriverFailedState();
376     /* Driver loading */
377     private State mDriverLoadingState = new DriverLoadingState();
378     /* Driver loaded */
379     private State mDriverLoadedState = new DriverLoadedState();
380     /* Driver loaded, waiting for supplicant to start */
381     private State mSupplicantStartingState = new SupplicantStartingState();
382     /* Driver loaded and supplicant ready */
383     private State mSupplicantStartedState = new SupplicantStartedState();
384     /* Waiting for supplicant to stop and monitor to exit */
385     private State mSupplicantStoppingState = new SupplicantStoppingState();
386     /* Driver start issued, waiting for completed event */
387     private State mDriverStartingState = new DriverStartingState();
388     /* Driver started */
389     private State mDriverStartedState = new DriverStartedState();
390     /* Driver stopping */
391     private State mDriverStoppingState = new DriverStoppingState();
392     /* Driver stopped */
393     private State mDriverStoppedState = new DriverStoppedState();
394     /* Scan for networks, no connection will be established */
395     private State mScanModeState = new ScanModeState();
396     /* Connecting to an access point */
397     private State mConnectModeState = new ConnectModeState();
398     /* Fetching IP after network connection (assoc+auth complete) */
399     private State mConnectingState = new ConnectingState();
400     /* Connected with IP addr */
401     private State mConnectedState = new ConnectedState();
402     /* disconnect issued, waiting for network disconnect confirmation */
403     private State mDisconnectingState = new DisconnectingState();
404     /* Network is not connected, supplicant assoc+auth is not complete */
405     private State mDisconnectedState = new DisconnectedState();
406     /* Waiting for WPS to be completed*/
407     private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
408
409     /* Soft Ap is running */
410     private State mSoftApStartedState = new SoftApStartedState();
411
412
413     /**
414      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
415      *         {@link WifiManager#WIFI_STATE_DISABLING},
416      *         {@link WifiManager#WIFI_STATE_ENABLED},
417      *         {@link WifiManager#WIFI_STATE_ENABLING},
418      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
419      *
420      */
421     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
422
423     /**
424      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
425      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
426      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
427      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
428      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
429      *
430      */
431     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
432
433     private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
434     private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
435
436     private static final int SCAN_REQUEST = 0;
437     private static final String ACTION_START_SCAN =
438         "com.android.server.WifiManager.action.START_SCAN";
439
440     /**
441      * Keep track of whether WIFI is running.
442      */
443     private boolean mIsRunning = false;
444
445     /**
446      * Keep track of whether we last told the battery stats we had started.
447      */
448     private boolean mReportedRunning = false;
449
450     /**
451      * Most recently set source of starting WIFI.
452      */
453     private final WorkSource mRunningWifiUids = new WorkSource();
454
455     /**
456      * The last reported UIDs that were responsible for starting WIFI.
457      */
458     private final WorkSource mLastRunningWifiUids = new WorkSource();
459
460     private final IBatteryStats mBatteryStats;
461
462     public WifiStateMachine(Context context, String wlanInterface) {
463         super(TAG);
464
465         mContext = context;
466         mInterfaceName = wlanInterface;
467
468         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
469         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
470
471         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
472         nwService = INetworkManagementService.Stub.asInterface(b);
473
474         mWifiMonitor = new WifiMonitor(this);
475         mDhcpInfoInternal = new DhcpInfoInternal();
476         mWifiInfo = new WifiInfo();
477         mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
478         mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
479         mLinkProperties = new LinkProperties();
480
481         mNetworkInfo.setIsAvailable(false);
482         mLinkProperties.clear();
483         mLastBssid = null;
484         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
485         mLastSignalLevel = -1;
486
487         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
488         Intent scanIntent = new Intent(ACTION_START_SCAN, null);
489         mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
490
491         mContext.registerReceiver(
492             new BroadcastReceiver() {
493                 @Override
494                 public void onReceive(Context context, Intent intent) {
495
496                     ArrayList<String> available = intent.getStringArrayListExtra(
497                             ConnectivityManager.EXTRA_AVAILABLE_TETHER);
498                     ArrayList<String> active = intent.getStringArrayListExtra(
499                             ConnectivityManager.EXTRA_ACTIVE_TETHER);
500                     updateTetherState(available, active);
501
502                 }
503             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
504
505         mContext.registerReceiver(
506                 new BroadcastReceiver() {
507                     @Override
508                     public void onReceive(Context context, Intent intent) {
509                         startScan(false);
510                     }
511                 },
512                 new IntentFilter(ACTION_START_SCAN));
513
514         mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
515
516         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
517         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
518
519         addState(mDefaultState);
520             addState(mInitialState, mDefaultState);
521             addState(mDriverUnloadingState, mDefaultState);
522             addState(mDriverUnloadedState, mDefaultState);
523                 addState(mDriverFailedState, mDriverUnloadedState);
524             addState(mDriverLoadingState, mDefaultState);
525             addState(mDriverLoadedState, mDefaultState);
526             addState(mSupplicantStartingState, mDefaultState);
527             addState(mSupplicantStartedState, mDefaultState);
528                 addState(mDriverStartingState, mSupplicantStartedState);
529                 addState(mDriverStartedState, mSupplicantStartedState);
530                     addState(mScanModeState, mDriverStartedState);
531                     addState(mConnectModeState, mDriverStartedState);
532                         addState(mConnectingState, mConnectModeState);
533                         addState(mConnectedState, mConnectModeState);
534                         addState(mDisconnectingState, mConnectModeState);
535                         addState(mDisconnectedState, mConnectModeState);
536                         addState(mWaitForWpsCompletionState, mConnectModeState);
537                 addState(mDriverStoppingState, mSupplicantStartedState);
538                 addState(mDriverStoppedState, mSupplicantStartedState);
539             addState(mSupplicantStoppingState, mDefaultState);
540             addState(mSoftApStartedState, mDefaultState);
541
542         setInitialState(mInitialState);
543
544         if (DBG) setDbg(true);
545
546         //start the state machine
547         start();
548     }
549
550     /*********************************************************
551      * Methods exposed for public use
552      ********************************************************/
553
554     /**
555      * TODO: doc
556      */
557     public boolean syncPingSupplicant(AsyncChannel channel) {
558         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
559         boolean result = (resultMsg.arg1 != FAILURE);
560         resultMsg.recycle();
561         return result;
562     }
563
564     /**
565      * TODO: doc
566      */
567     public void startScan(boolean forceActive) {
568         sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
569                 SCAN_ACTIVE : SCAN_PASSIVE, 0));
570     }
571
572     /**
573      * TODO: doc
574      */
575     public void setWifiEnabled(boolean enable) {
576         mLastEnableUid.set(Binder.getCallingUid());
577         if (enable) {
578             /* Argument is the state that is entered prior to load */
579             sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
580             sendMessage(CMD_START_SUPPLICANT);
581         } else {
582             sendMessage(CMD_STOP_SUPPLICANT);
583             /* Argument is the state that is entered upon success */
584             sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
585         }
586     }
587
588     /**
589      * TODO: doc
590      */
591     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
592         mLastApEnableUid.set(Binder.getCallingUid());
593         if (enable) {
594             /* Argument is the state that is entered prior to load */
595             sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
596             sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
597         } else {
598             sendMessage(CMD_STOP_AP);
599             /* Argument is the state that is entered upon success */
600             sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
601         }
602     }
603
604     public void setWifiApConfiguration(WifiConfiguration config) {
605         sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
606     }
607
608     public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
609         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
610         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
611         resultMsg.recycle();
612         return ret;
613     }
614
615     /**
616      * TODO: doc
617      */
618     public int syncGetWifiState() {
619         return mWifiState.get();
620     }
621
622     /**
623      * TODO: doc
624      */
625     public String syncGetWifiStateByName() {
626         switch (mWifiState.get()) {
627             case WIFI_STATE_DISABLING:
628                 return "disabling";
629             case WIFI_STATE_DISABLED:
630                 return "disabled";
631             case WIFI_STATE_ENABLING:
632                 return "enabling";
633             case WIFI_STATE_ENABLED:
634                 return "enabled";
635             case WIFI_STATE_UNKNOWN:
636                 return "unknown state";
637             default:
638                 return "[invalid state]";
639         }
640     }
641
642     /**
643      * TODO: doc
644      */
645     public int syncGetWifiApState() {
646         return mWifiApState.get();
647     }
648
649     /**
650      * TODO: doc
651      */
652     public String syncGetWifiApStateByName() {
653         switch (mWifiApState.get()) {
654             case WIFI_AP_STATE_DISABLING:
655                 return "disabling";
656             case WIFI_AP_STATE_DISABLED:
657                 return "disabled";
658             case WIFI_AP_STATE_ENABLING:
659                 return "enabling";
660             case WIFI_AP_STATE_ENABLED:
661                 return "enabled";
662             case WIFI_AP_STATE_FAILED:
663                 return "failed";
664             default:
665                 return "[invalid state]";
666         }
667     }
668
669     /**
670      * Get status information for the current connection, if any.
671      * @return a {@link WifiInfo} object containing information about the current connection
672      *
673      */
674     public WifiInfo syncRequestConnectionInfo() {
675         return mWifiInfo;
676     }
677
678     public DhcpInfo syncGetDhcpInfo() {
679         synchronized (mDhcpInfoInternal) {
680             return mDhcpInfoInternal.makeDhcpInfo();
681         }
682     }
683
684     /**
685      * TODO: doc
686      */
687     public void setDriverStart(boolean enable) {
688         if (enable) {
689             sendMessage(CMD_START_DRIVER);
690         } else {
691             sendMessage(CMD_STOP_DRIVER);
692         }
693     }
694
695     /**
696      * TODO: doc
697      */
698     public void setScanOnlyMode(boolean enable) {
699       if (enable) {
700           sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
701       } else {
702           sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
703       }
704     }
705
706     /**
707      * TODO: doc
708      */
709     public void setScanType(boolean active) {
710       if (active) {
711           sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
712       } else {
713           sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
714       }
715     }
716
717     /**
718      * TODO: doc
719      */
720     public List<ScanResult> syncGetScanResultsList() {
721         return mScanResults;
722     }
723
724     /**
725      * Disconnect from Access Point
726      */
727     public void disconnectCommand() {
728         sendMessage(CMD_DISCONNECT);
729     }
730
731     /**
732      * Initiate a reconnection to AP
733      */
734     public void reconnectCommand() {
735         sendMessage(CMD_RECONNECT);
736     }
737
738     /**
739      * Initiate a re-association to AP
740      */
741     public void reassociateCommand() {
742         sendMessage(CMD_REASSOCIATE);
743     }
744
745     /**
746      * Add a network synchronously
747      *
748      * @return network id of the new network
749      */
750     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
751         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
752         int result = resultMsg.arg1;
753         resultMsg.recycle();
754         return result;
755     }
756
757     public List<WifiConfiguration> syncGetConfiguredNetworks() {
758         return WifiConfigStore.getConfiguredNetworks();
759     }
760
761     /**
762      * Delete a network
763      *
764      * @param networkId id of the network to be removed
765      */
766     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
767         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
768         boolean result = (resultMsg.arg1 != FAILURE);
769         resultMsg.recycle();
770         return result;
771     }
772
773     /**
774      * Enable a network
775      *
776      * @param netId network id of the network
777      * @param disableOthers true, if all other networks have to be disabled
778      * @return {@code true} if the operation succeeds, {@code false} otherwise
779      */
780     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
781         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
782                 disableOthers ? 1 : 0);
783         boolean result = (resultMsg.arg1 != FAILURE);
784         resultMsg.recycle();
785         return result;
786     }
787
788     /**
789      * Disable a network
790      *
791      * @param netId network id of the network
792      * @return {@code true} if the operation succeeds, {@code false} otherwise
793      */
794     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
795         Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId);
796         boolean result = (resultMsg.arg1 != FAILURE);
797         resultMsg.recycle();
798         return result;
799     }
800
801     /**
802      * Blacklist a BSSID. This will avoid the AP if there are
803      * alternate APs to connect
804      *
805      * @param bssid BSSID of the network
806      */
807     public void addToBlacklist(String bssid) {
808         sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
809     }
810
811     /**
812      * Clear the blacklist list
813      *
814      */
815     public void clearBlacklist() {
816         sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
817     }
818
819     public void connectNetwork(int netId) {
820         sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
821     }
822
823     public void connectNetwork(WifiConfiguration wifiConfig) {
824         /* arg1 is used to indicate netId, force a netId value of
825          * WifiConfiguration.INVALID_NETWORK_ID when we are passing
826          * a configuration since the default value of 0 is a valid netId
827          */
828         sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
829                 0, wifiConfig));
830     }
831
832     public void saveNetwork(WifiConfiguration wifiConfig) {
833         sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig));
834     }
835
836     public void forgetNetwork(int netId) {
837         sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
838     }
839
840     public void startWps(Messenger replyTo, WpsConfiguration config) {
841         Message msg = obtainMessage(CMD_START_WPS, config);
842         msg.replyTo = replyTo;
843         sendMessage(msg);
844     }
845
846     public void enableRssiPolling(boolean enabled) {
847        sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
848     }
849
850     public void enableBackgroundScan(boolean enabled) {
851        sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
852     }
853
854     public void enableAllNetworks() {
855         sendMessage(CMD_ENABLE_ALL_NETWORKS);
856     }
857
858     /**
859      * Start packet filtering
860      */
861     public void startPacketFiltering() {
862         sendMessage(CMD_START_PACKET_FILTERING);
863     }
864
865     /**
866      * Stop packet filtering
867      */
868     public void stopPacketFiltering() {
869         sendMessage(CMD_STOP_PACKET_FILTERING);
870     }
871
872     /**
873      * Set high performance mode of operation.
874      * Enabling would set active power mode and disable suspend optimizations;
875      * disabling would set auto power mode and enable suspend optimizations
876      * @param enable true if enable, false otherwise
877      */
878     public void setHighPerfModeEnabled(boolean enable) {
879         sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
880     }
881
882     /**
883      * Set the country code
884      * @param countryCode following ISO 3166 format
885      * @param persist {@code true} if the setting should be remembered.
886      */
887     public void setCountryCode(String countryCode, boolean persist) {
888         if (persist) {
889             Settings.Secure.putString(mContext.getContentResolver(),
890                     Settings.Secure.WIFI_COUNTRY_CODE,
891                     countryCode);
892         }
893         sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
894     }
895
896     /**
897      * Set the operational frequency band
898      * @param band
899      * @param persist {@code true} if the setting should be remembered.
900      */
901     public void setFrequencyBand(int band, boolean persist) {
902         if (persist) {
903             Settings.Secure.putInt(mContext.getContentResolver(),
904                     Settings.Secure.WIFI_FREQUENCY_BAND,
905                     band);
906         }
907         sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
908     }
909
910     /**
911      * Returns the operational frequency band
912      */
913     public int getFrequencyBand() {
914         return mFrequencyBand.get();
915     }
916
917     /**
918      * Returns the wifi configuration file
919      */
920     public String getConfigFile() {
921         return WifiConfigStore.getConfigFile();
922     }
923
924     /**
925      * Send a message indicating bluetooth adapter connection state changed
926      */
927     public void sendBluetoothAdapterStateChange(int state) {
928         sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
929     }
930
931     /**
932      * Save configuration on supplicant
933      *
934      * @return {@code true} if the operation succeeds, {@code false} otherwise
935      *
936      * TODO: deprecate this
937      */
938     public boolean syncSaveConfig(AsyncChannel channel) {
939         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
940         boolean result = (resultMsg.arg1 != FAILURE);
941         resultMsg.recycle();
942         return result;
943     }
944
945     /**
946      * Request a wakelock with connectivity service to
947      * keep the device awake until we hand-off from wifi
948      * to an alternate network
949      */
950     public void requestCmWakeLock() {
951         sendMessage(CMD_REQUEST_CM_WAKELOCK);
952     }
953
954     public void updateBatteryWorkSource(WorkSource newSource) {
955         synchronized (mRunningWifiUids) {
956             try {
957                 if (newSource != null) {
958                     mRunningWifiUids.set(newSource);
959                 }
960                 if (mIsRunning) {
961                     if (mReportedRunning) {
962                         // If the work source has changed since last time, need
963                         // to remove old work from battery stats.
964                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
965                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
966                                     mRunningWifiUids);
967                             mLastRunningWifiUids.set(mRunningWifiUids);
968                         }
969                     } else {
970                         // Now being started, report it.
971                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
972                         mLastRunningWifiUids.set(mRunningWifiUids);
973                         mReportedRunning = true;
974                     }
975                 } else {
976                     if (mReportedRunning) {
977                         // Last reported we were running, time to stop.
978                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
979                         mLastRunningWifiUids.clear();
980                         mReportedRunning = false;
981                     }
982                 }
983                 mWakeLock.setWorkSource(newSource);
984             } catch (RemoteException ignore) {
985             }
986         }
987     }
988
989     @Override
990     public String toString() {
991         StringBuffer sb = new StringBuffer();
992         String LS = System.getProperty("line.separator");
993         sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
994         sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
995         sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
996         sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
997         sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
998         sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
999         sb.append("mLastBssid ").append(mLastBssid).append(LS);
1000         sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
1001         sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
1002         sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
1003         sb.append("Supplicant status").append(LS)
1004                 .append(WifiNative.statusCommand()).append(LS).append(LS);
1005
1006         sb.append(WifiConfigStore.dump());
1007         return sb.toString();
1008     }
1009
1010     /*********************************************************
1011      * Internal private functions
1012      ********************************************************/
1013
1014     private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
1015
1016         boolean wifiTethered = false;
1017         boolean wifiAvailable = false;
1018
1019         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1020         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1021
1022         if (mCm == null) {
1023             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1024         }
1025
1026         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1027
1028         for (String intf : available) {
1029             for (String regex : wifiRegexs) {
1030                 if (intf.matches(regex)) {
1031
1032                     InterfaceConfiguration ifcg = null;
1033                     try {
1034                         ifcg = service.getInterfaceConfig(intf);
1035                         if (ifcg != null) {
1036                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
1037                             ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
1038                                     "192.168.43.1"), 24);
1039                             ifcg.interfaceFlags = "[up]";
1040
1041                             service.setInterfaceConfig(intf, ifcg);
1042                         }
1043                     } catch (Exception e) {
1044                         Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
1045                         setWifiApEnabled(null, false);
1046                         return;
1047                     }
1048
1049                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1050                         Log.e(TAG, "Error tethering on " + intf);
1051                         setWifiApEnabled(null, false);
1052                         return;
1053                     }
1054                     break;
1055                 }
1056             }
1057         }
1058     }
1059
1060     /**
1061      * Set the country code from the system setting value, if any.
1062      */
1063     private void setCountryCode() {
1064         String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1065                 Settings.Secure.WIFI_COUNTRY_CODE);
1066         if (countryCode != null && !countryCode.isEmpty()) {
1067             setCountryCode(countryCode, false);
1068         } else {
1069             //use driver default
1070         }
1071     }
1072
1073     /**
1074      * Set the frequency band from the system setting value, if any.
1075      */
1076     private void setFrequencyBand() {
1077         int band = Settings.Secure.getInt(mContext.getContentResolver(),
1078                 Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1079         setFrequencyBand(band, false);
1080     }
1081
1082     private void setWifiState(int wifiState) {
1083         final int previousWifiState = mWifiState.get();
1084
1085         try {
1086             if (wifiState == WIFI_STATE_ENABLED) {
1087                 mBatteryStats.noteWifiOn();
1088             } else if (wifiState == WIFI_STATE_DISABLED) {
1089                 mBatteryStats.noteWifiOff();
1090             }
1091         } catch (RemoteException e) {
1092             Log.e(TAG, "Failed to note battery stats in wifi");
1093         }
1094
1095         mWifiState.set(wifiState);
1096
1097         if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName());
1098
1099         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1100         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1101         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1102         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1103         mContext.sendStickyBroadcast(intent);
1104     }
1105
1106     private void setWifiApState(int wifiApState) {
1107         final int previousWifiApState = mWifiApState.get();
1108
1109         try {
1110             if (wifiApState == WIFI_AP_STATE_ENABLED) {
1111                 mBatteryStats.noteWifiOn();
1112             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1113                 mBatteryStats.noteWifiOff();
1114             }
1115         } catch (RemoteException e) {
1116             Log.d(TAG, "Failed to note battery stats in wifi");
1117         }
1118
1119         // Update state
1120         mWifiApState.set(wifiApState);
1121
1122         if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName());
1123
1124         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1125         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1126         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1127         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1128         mContext.sendStickyBroadcast(intent);
1129     }
1130
1131     /**
1132      * Parse the scan result line passed to us by wpa_supplicant (helper).
1133      * @param line the line to parse
1134      * @return the {@link ScanResult} object
1135      */
1136     private ScanResult parseScanResult(String line) {
1137         ScanResult scanResult = null;
1138         if (line != null) {
1139             /*
1140              * Cache implementation (LinkedHashMap) is not synchronized, thus,
1141              * must synchronized here!
1142              */
1143             synchronized (mScanResultCache) {
1144                 String[] result = scanResultPattern.split(line);
1145                 if (3 <= result.length && result.length <= 5) {
1146                     String bssid = result[0];
1147                     // bssid | frequency | level | flags | ssid
1148                     int frequency;
1149                     int level;
1150                     try {
1151                         frequency = Integer.parseInt(result[1]);
1152                         level = Integer.parseInt(result[2]);
1153                         /* some implementations avoid negative values by adding 256
1154                          * so we need to adjust for that here.
1155                          */
1156                         if (level > 0) level -= 256;
1157                     } catch (NumberFormatException e) {
1158                         frequency = 0;
1159                         level = 0;
1160                     }
1161
1162                     /*
1163                      * The formatting of the results returned by
1164                      * wpa_supplicant is intended to make the fields
1165                      * line up nicely when printed,
1166                      * not to make them easy to parse. So we have to
1167                      * apply some heuristics to figure out which field
1168                      * is the SSID and which field is the flags.
1169                      */
1170                     String ssid;
1171                     String flags;
1172                     if (result.length == 4) {
1173                         if (result[3].charAt(0) == '[') {
1174                             flags = result[3];
1175                             ssid = "";
1176                         } else {
1177                             flags = "";
1178                             ssid = result[3];
1179                         }
1180                     } else if (result.length == 5) {
1181                         flags = result[3];
1182                         ssid = result[4];
1183                     } else {
1184                         // Here, we must have 3 fields: no flags and ssid
1185                         // set
1186                         flags = "";
1187                         ssid = "";
1188                     }
1189
1190                     // bssid + ssid is the hash key
1191                     String key = bssid + ssid;
1192                     scanResult = mScanResultCache.get(key);
1193                     if (scanResult != null) {
1194                         scanResult.level = level;
1195                         scanResult.SSID = ssid;
1196                         scanResult.capabilities = flags;
1197                         scanResult.frequency = frequency;
1198                     } else {
1199                         // Do not add scan results that have no SSID set
1200                         if (0 < ssid.trim().length()) {
1201                             scanResult =
1202                                 new ScanResult(
1203                                     ssid, bssid, flags, level, frequency);
1204                             mScanResultCache.put(key, scanResult);
1205                         }
1206                     }
1207                 } else {
1208                     Log.w(TAG, "Misformatted scan result text with " +
1209                           result.length + " fields: " + line);
1210                 }
1211             }
1212         }
1213
1214         return scanResult;
1215     }
1216
1217     /**
1218      * scanResults input format
1219      * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
1220      * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
1221      */
1222     private void setScanResults(String scanResults) {
1223         if (scanResults == null) {
1224             return;
1225         }
1226
1227         List<ScanResult> scanList = new ArrayList<ScanResult>();
1228
1229         int lineCount = 0;
1230
1231         int scanResultsLen = scanResults.length();
1232         // Parse the result string, keeping in mind that the last line does
1233         // not end with a newline.
1234         for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
1235             if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
1236                 ++lineCount;
1237
1238                 if (lineCount == 1) {
1239                     lineBeg = lineEnd + 1;
1240                     continue;
1241                 }
1242                 if (lineEnd > lineBeg) {
1243                     String line = scanResults.substring(lineBeg, lineEnd);
1244                     ScanResult scanResult = parseScanResult(line);
1245                     if (scanResult != null) {
1246                         scanList.add(scanResult);
1247                     } else {
1248                         //TODO: hidden network handling
1249                     }
1250                 }
1251                 lineBeg = lineEnd + 1;
1252             }
1253         }
1254
1255         mScanResults = scanList;
1256     }
1257
1258     private String fetchSSID() {
1259         String status = WifiNative.statusCommand();
1260         if (status == null) {
1261             return null;
1262         }
1263         // extract ssid from a series of "name=value"
1264         String[] lines = status.split("\n");
1265         for (String line : lines) {
1266             String[] prop = line.split(" *= *");
1267             if (prop.length < 2) continue;
1268             String name = prop[0];
1269             String value = prop[1];
1270             if (name.equalsIgnoreCase("ssid")) return value;
1271         }
1272         return null;
1273     }
1274
1275     /*
1276      * Fetch RSSI and linkspeed on current connection
1277      */
1278     private void fetchRssiAndLinkSpeedNative() {
1279         int newRssi = WifiNative.getRssiCommand();
1280         if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1281             /* some implementations avoid negative values by adding 256
1282              * so we need to adjust for that here.
1283              */
1284             if (newRssi > 0) newRssi -= 256;
1285             mWifiInfo.setRssi(newRssi);
1286             /*
1287              * Rather then sending the raw RSSI out every time it
1288              * changes, we precalculate the signal level that would
1289              * be displayed in the status bar, and only send the
1290              * broadcast if that much more coarse-grained number
1291              * changes. This cuts down greatly on the number of
1292              * broadcasts, at the cost of not mWifiInforming others
1293              * interested in RSSI of all the changes in signal
1294              * level.
1295              */
1296             // TODO: The second arg to the call below needs to be a symbol somewhere, but
1297             // it's actually the size of an array of icons that's private
1298             // to StatusBar Policy.
1299             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
1300             if (newSignalLevel != mLastSignalLevel) {
1301                 sendRssiChangeBroadcast(newRssi);
1302             }
1303             mLastSignalLevel = newSignalLevel;
1304         } else {
1305             mWifiInfo.setRssi(MIN_RSSI);
1306         }
1307         int newLinkSpeed = WifiNative.getLinkSpeedCommand();
1308         if (newLinkSpeed != -1) {
1309             mWifiInfo.setLinkSpeed(newLinkSpeed);
1310         }
1311     }
1312
1313     private void setHighPerfModeEnabledNative(boolean enable) {
1314         if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
1315             Log.e(TAG, "set suspend optimizations failed!");
1316         }
1317         if (enable) {
1318             if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
1319                 Log.e(TAG, "set power mode active failed!");
1320             }
1321         } else {
1322             if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
1323                 Log.e(TAG, "set power mode auto failed!");
1324             }
1325         }
1326     }
1327
1328     private void configureLinkProperties() {
1329         if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1330             mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
1331         } else {
1332             synchronized (mDhcpInfoInternal) {
1333                 mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1334             }
1335             mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1336         }
1337         mLinkProperties.setInterfaceName(mInterfaceName);
1338         Log.d(TAG, "netId=" + mLastNetworkId  + " Link configured: " + mLinkProperties.toString());
1339     }
1340
1341     private int getMaxDhcpRetries() {
1342         return Settings.Secure.getInt(mContext.getContentResolver(),
1343                                       Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1344                                       DEFAULT_MAX_DHCP_RETRIES);
1345     }
1346
1347     private void sendScanResultsAvailableBroadcast() {
1348         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1349         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1350         mContext.sendBroadcast(intent);
1351     }
1352
1353     private void sendRssiChangeBroadcast(final int newRssi) {
1354         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1355         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1356         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1357         mContext.sendBroadcast(intent);
1358     }
1359
1360     private void sendNetworkStateChangeBroadcast(String bssid) {
1361         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1362         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1363                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1364         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
1365         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1366         if (bssid != null)
1367             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1368         mContext.sendStickyBroadcast(intent);
1369     }
1370
1371     private void sendErrorBroadcast(int errorCode) {
1372         Intent intent = new Intent(WifiManager.ERROR_ACTION);
1373         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1374         intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
1375         mContext.sendBroadcast(intent);
1376     }
1377
1378     private void sendLinkConfigurationChangedBroadcast() {
1379         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1380         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1381         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1382         mContext.sendBroadcast(intent);
1383     }
1384
1385     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1386         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1387         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1388         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1389         mContext.sendBroadcast(intent);
1390     }
1391
1392     /**
1393      * Record the detailed state of a network.
1394      * @param state the new @{code DetailedState}
1395      */
1396     private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1397         Log.d(TAG, "setDetailed state, old ="
1398                 + mNetworkInfo.getDetailedState() + " and new state=" + state);
1399         if (state != mNetworkInfo.getDetailedState()) {
1400             mNetworkInfo.setDetailedState(state, null, null);
1401         }
1402     }
1403
1404     private DetailedState getNetworkDetailedState() {
1405         return mNetworkInfo.getDetailedState();
1406     }
1407
1408     /**
1409      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1410      * using the interface, stopping DHCP & disabling interface
1411      */
1412     private void handleNetworkDisconnect() {
1413         Log.d(TAG, "Reset connections and stopping DHCP");
1414
1415         /*
1416          * stop DHCP
1417          */
1418        NetworkUtils.resetConnections(mInterfaceName);
1419
1420         if (mDhcpStateMachine != null) {
1421             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1422             mDhcpStateMachine.quit();
1423             mDhcpStateMachine = null;
1424         }
1425
1426         /* Disable interface */
1427         NetworkUtils.disableInterface(mInterfaceName);
1428
1429         /* Reset data structures */
1430         mWifiInfo.setInetAddress(null);
1431         mWifiInfo.setBSSID(null);
1432         mWifiInfo.setSSID(null);
1433         mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1434         mWifiInfo.setRssi(MIN_RSSI);
1435         mWifiInfo.setLinkSpeed(-1);
1436
1437         /* send event to CM & network change broadcast */
1438         setNetworkDetailedState(DetailedState.DISCONNECTED);
1439         sendNetworkStateChangeBroadcast(mLastBssid);
1440
1441         /* Clear network properties */
1442         mLinkProperties.clear();
1443         /* Clear IP settings if the network used DHCP */
1444         if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1445             WifiConfigStore.clearIpConfiguration(mLastNetworkId);
1446         }
1447
1448         mLastBssid= null;
1449         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1450     }
1451
1452     void handlePreDhcpSetup() {
1453         if (!mBluetoothConnectionActive) {
1454             /*
1455              * There are problems setting the Wi-Fi driver's power
1456              * mode to active when bluetooth coexistence mode is
1457              * enabled or sense.
1458              * <p>
1459              * We set Wi-Fi to active mode when
1460              * obtaining an IP address because we've found
1461              * compatibility issues with some routers with low power
1462              * mode.
1463              * <p>
1464              * In order for this active power mode to properly be set,
1465              * we disable coexistence mode until we're done with
1466              * obtaining an IP address.  One exception is if we
1467              * are currently connected to a headset, since disabling
1468              * coexistence would interrupt that connection.
1469              */
1470             // Disable the coexistence mode
1471             WifiNative.setBluetoothCoexistenceModeCommand(
1472                     WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1473         }
1474
1475         mPowerMode =  WifiNative.getPowerModeCommand();
1476         if (mPowerMode < 0) {
1477             // Handle the case where supplicant driver does not support
1478             // getPowerModeCommand.
1479             mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
1480         }
1481         if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
1482             WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
1483         }
1484     }
1485
1486
1487     void handlePostDhcpSetup() {
1488         /* restore power mode */
1489         WifiNative.setPowerModeCommand(mPowerMode);
1490
1491         // Set the coexistence mode back to its default value
1492         WifiNative.setBluetoothCoexistenceModeCommand(
1493                 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1494     }
1495
1496     private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
1497         synchronized (mDhcpInfoInternal) {
1498             mDhcpInfoInternal = dhcpInfoInternal;
1499         }
1500         mLastSignalLevel = -1; // force update of signal strength
1501         WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
1502         InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
1503         mWifiInfo.setInetAddress(addr);
1504         if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1505             //DHCP renewal in connected state
1506             LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
1507             linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1508             linkProperties.setInterfaceName(mInterfaceName);
1509             if (!linkProperties.equals(mLinkProperties)) {
1510                 Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
1511                     + " old: " + mLinkProperties + "new: " + linkProperties);
1512                 NetworkUtils.resetConnections(mInterfaceName);
1513                 mLinkProperties = linkProperties;
1514                 sendLinkConfigurationChangedBroadcast();
1515             }
1516         } else {
1517             configureLinkProperties();
1518             setNetworkDetailedState(DetailedState.CONNECTED);
1519             sendNetworkStateChangeBroadcast(mLastBssid);
1520         }
1521     }
1522
1523     private void handleFailedIpConfiguration() {
1524         Log.e(TAG, "IP configuration failed");
1525
1526         mWifiInfo.setInetAddress(null);
1527         /**
1528          * If we've exceeded the maximum number of retries for DHCP
1529          * to a given network, disable the network
1530          */
1531         if (++mReconnectCount > getMaxDhcpRetries()) {
1532             Log.e(TAG, "Failed " +
1533                     mReconnectCount + " times, Disabling " + mLastNetworkId);
1534             WifiConfigStore.disableNetwork(mLastNetworkId);
1535             mReconnectCount = 0;
1536         }
1537
1538         /* DHCP times out after about 30 seconds, we do a
1539          * disconnect and an immediate reconnect to try again
1540          */
1541         WifiNative.disconnectCommand();
1542         WifiNative.reconnectCommand();
1543     }
1544
1545     private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
1546         if (config == null) {
1547             config = WifiApConfigStore.getApConfiguration();
1548         } else {
1549             WifiApConfigStore.setApConfiguration(config);
1550         }
1551         try {
1552             if (currentStatus == SOFT_AP_STOPPED) {
1553                 nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1554             } else if (currentStatus == SOFT_AP_RUNNING) {
1555                 nwService.setAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1556             }
1557         } catch (Exception e) {
1558             Log.e(TAG, "Exception in softap start " + e);
1559             try {
1560                 nwService.stopAccessPoint();
1561                 nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1562             } catch (Exception ee) {
1563                 Log.e(TAG, "Exception during softap restart : " + ee);
1564                 return false;
1565             }
1566         }
1567         return true;
1568     }
1569
1570
1571     /*********************************************************
1572      * Notifications from WifiMonitor
1573      ********************************************************/
1574
1575     /**
1576      * Stores supplicant state change information passed from WifiMonitor
1577      */
1578     static class StateChangeResult {
1579         StateChangeResult(int networkId, String BSSID, SupplicantState state) {
1580             this.state = state;
1581             this.BSSID = BSSID;
1582             this.networkId = networkId;
1583         }
1584         int networkId;
1585         String BSSID;
1586         SupplicantState state;
1587     }
1588
1589     /**
1590      * Send the tracker a notification that a user provided
1591      * configuration caused authentication failure - this could
1592      * be a password failure or a EAP authentication failure
1593      */
1594     void notifyAuthenticationFailure() {
1595         sendMessage(AUTHENTICATION_FAILURE_EVENT);
1596     }
1597
1598     /**
1599      * Send a notification that the supplicant has detected overlapped
1600      * WPS sessions
1601      */
1602     void notifyWpsOverlap() {
1603         sendMessage(WPS_OVERLAP_EVENT);
1604     }
1605
1606     /**
1607      * Send the tracker a notification that a connection to the supplicant
1608      * daemon has been established.
1609      */
1610     void notifySupplicantConnection() {
1611         sendMessage(SUP_CONNECTION_EVENT);
1612     }
1613
1614     /**
1615      * Send the tracker a notification that connection to the supplicant
1616      * daemon is lost
1617      */
1618     void notifySupplicantLost() {
1619         sendMessage(SUP_DISCONNECTION_EVENT);
1620     }
1621
1622     /**
1623      * Send the tracker a notification that the state of Wifi connectivity
1624      * has changed.
1625      * @param networkId the configured network on which the state change occurred
1626      * @param newState the new network state
1627      * @param BSSID when the new state is {@link DetailedState#CONNECTED
1628      * NetworkInfo.DetailedState.CONNECTED},
1629      * this is the MAC address of the access point. Otherwise, it
1630      * is {@code null}.
1631      */
1632     void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
1633         if (newState == NetworkInfo.DetailedState.CONNECTED) {
1634             sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, networkId, 0, BSSID));
1635         } else {
1636             sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, networkId, 0, BSSID));
1637         }
1638     }
1639
1640     /**
1641      * Send the tracker a notification that the state of the supplicant
1642      * has changed.
1643      * @param networkId the configured network on which the state change occurred
1644      * @param newState the new {@code SupplicantState}
1645      */
1646     void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
1647         sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
1648                 new StateChangeResult(networkId, BSSID, newState)));
1649     }
1650
1651     /**
1652      * Send the tracker a notification that a scan has completed, and results
1653      * are available.
1654      */
1655     void notifyScanResultsAvailable() {
1656         /**
1657          * Switch scan mode over to passive.
1658          * Turning off scan-only mode happens only in "Connect" mode
1659          */
1660         setScanType(false);
1661         sendMessage(SCAN_RESULTS_EVENT);
1662     }
1663
1664     void notifyDriverStarted() {
1665         sendMessage(DRIVER_START_EVENT);
1666     }
1667
1668     void notifyDriverStopped() {
1669         sendMessage(DRIVER_STOP_EVENT);
1670     }
1671
1672     void notifyDriverHung() {
1673         setWifiEnabled(false);
1674         setWifiEnabled(true);
1675     }
1676
1677     /********************************************************
1678      * HSM states
1679      *******************************************************/
1680
1681     class DefaultState extends State {
1682         @Override
1683         public boolean processMessage(Message message) {
1684             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1685             switch (message.what) {
1686                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1687                     mBluetoothConnectionActive = (message.arg1 !=
1688                             BluetoothAdapter.STATE_DISCONNECTED);
1689                     break;
1690                     /* Synchronous call returns */
1691                 case CMD_PING_SUPPLICANT:
1692                 case CMD_ENABLE_NETWORK:
1693                 case CMD_DISABLE_NETWORK:
1694                 case CMD_ADD_OR_UPDATE_NETWORK:
1695                 case CMD_REMOVE_NETWORK:
1696                 case CMD_SAVE_CONFIG:
1697                     mReplyChannel.replyToMessage(message, message.what, FAILURE);
1698                     break;
1699                 case CMD_ENABLE_RSSI_POLL:
1700                     mEnableRssiPolling = (message.arg1 == 1);
1701                     break;
1702                 case CMD_ENABLE_BACKGROUND_SCAN:
1703                     mEnableBackgroundScan = (message.arg1 == 1);
1704                     break;
1705                 case CMD_SET_AP_CONFIG:
1706                     WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
1707                     break;
1708                 case CMD_GET_AP_CONFIG:
1709                     WifiConfiguration config = WifiApConfigStore.getApConfiguration();
1710                     mReplyChannel.replyToMessage(message, message.what, config);
1711                     break;
1712                     /* Discard */
1713                 case CMD_LOAD_DRIVER:
1714                 case CMD_UNLOAD_DRIVER:
1715                 case CMD_START_SUPPLICANT:
1716                 case CMD_STOP_SUPPLICANT:
1717                 case CMD_START_DRIVER:
1718                 case CMD_STOP_DRIVER:
1719                 case CMD_START_AP:
1720                 case CMD_STOP_AP:
1721                 case CMD_START_SCAN:
1722                 case CMD_DISCONNECT:
1723                 case CMD_RECONNECT:
1724                 case CMD_REASSOCIATE:
1725                 case SUP_CONNECTION_EVENT:
1726                 case SUP_DISCONNECTION_EVENT:
1727                 case DRIVER_START_EVENT:
1728                 case DRIVER_STOP_EVENT:
1729                 case NETWORK_CONNECTION_EVENT:
1730                 case NETWORK_DISCONNECTION_EVENT:
1731                 case SCAN_RESULTS_EVENT:
1732                 case SUPPLICANT_STATE_CHANGE_EVENT:
1733                 case AUTHENTICATION_FAILURE_EVENT:
1734                 case WPS_OVERLAP_EVENT:
1735                 case CMD_BLACKLIST_NETWORK:
1736                 case CMD_CLEAR_BLACKLIST:
1737                 case CMD_SET_SCAN_MODE:
1738                 case CMD_SET_SCAN_TYPE:
1739                 case CMD_SET_HIGH_PERF_MODE:
1740                 case CMD_SET_COUNTRY_CODE:
1741                 case CMD_SET_FREQUENCY_BAND:
1742                 case CMD_REQUEST_CM_WAKELOCK:
1743                 case CMD_CONNECT_NETWORK:
1744                 case CMD_SAVE_NETWORK:
1745                 case CMD_FORGET_NETWORK:
1746                 case CMD_RSSI_POLL:
1747                 case CMD_ENABLE_ALL_NETWORKS:
1748                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1749                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1750                     break;
1751                 case CMD_START_WPS:
1752                     /* Return failure when the state machine cannot handle WPS initiation*/
1753                     mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
1754                                 new WpsResult(Status.FAILURE));
1755                     break;
1756                 default:
1757                     Log.e(TAG, "Error! unhandled message" + message);
1758                     break;
1759             }
1760             return HANDLED;
1761         }
1762     }
1763
1764     class InitialState extends State {
1765         @Override
1766         //TODO: could move logging into a common class
1767         public void enter() {
1768             if (DBG) Log.d(TAG, getName() + "\n");
1769             // [31-8] Reserved for future use
1770             // [7 - 0] HSM state change
1771             // 50021 wifi_state_changed (custom|1|5)
1772             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1773
1774             WifiApConfigStore.initialize(mContext);
1775
1776             if (WifiNative.isDriverLoaded()) {
1777                 transitionTo(mDriverLoadedState);
1778             }
1779             else {
1780                 transitionTo(mDriverUnloadedState);
1781             }
1782         }
1783     }
1784
1785     class DriverLoadingState extends State {
1786         @Override
1787         public void enter() {
1788             if (DBG) Log.d(TAG, getName() + "\n");
1789             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1790
1791             final Message message = new Message();
1792             message.copyFrom(getCurrentMessage());
1793             /* TODO: add a timeout to fail when driver load is hung.
1794              * Similarly for driver unload.
1795              */
1796             new Thread(new Runnable() {
1797                 public void run() {
1798                     mWakeLock.acquire();
1799                     //enabling state
1800                     switch(message.arg1) {
1801                         case WIFI_STATE_ENABLING:
1802                             setWifiState(WIFI_STATE_ENABLING);
1803                             break;
1804                         case WIFI_AP_STATE_ENABLING:
1805                             setWifiApState(WIFI_AP_STATE_ENABLING);
1806                             break;
1807                     }
1808
1809                     if(WifiNative.loadDriver()) {
1810                         Log.d(TAG, "Driver load successful");
1811                         sendMessage(CMD_LOAD_DRIVER_SUCCESS);
1812                     } else {
1813                         Log.e(TAG, "Failed to load driver!");
1814                         switch(message.arg1) {
1815                             case WIFI_STATE_ENABLING:
1816                                 setWifiState(WIFI_STATE_UNKNOWN);
1817                                 break;
1818                             case WIFI_AP_STATE_ENABLING:
1819                                 setWifiApState(WIFI_AP_STATE_FAILED);
1820                                 break;
1821                         }
1822                         sendMessage(CMD_LOAD_DRIVER_FAILURE);
1823                     }
1824                     mWakeLock.release();
1825                 }
1826             }).start();
1827         }
1828
1829         @Override
1830         public boolean processMessage(Message message) {
1831             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1832             switch (message.what) {
1833                 case CMD_LOAD_DRIVER_SUCCESS:
1834                     transitionTo(mDriverLoadedState);
1835                     break;
1836                 case CMD_LOAD_DRIVER_FAILURE:
1837                     transitionTo(mDriverFailedState);
1838                     break;
1839                 case CMD_LOAD_DRIVER:
1840                 case CMD_UNLOAD_DRIVER:
1841                 case CMD_START_SUPPLICANT:
1842                 case CMD_STOP_SUPPLICANT:
1843                 case CMD_START_AP:
1844                 case CMD_STOP_AP:
1845                 case CMD_START_DRIVER:
1846                 case CMD_STOP_DRIVER:
1847                 case CMD_SET_SCAN_MODE:
1848                 case CMD_SET_SCAN_TYPE:
1849                 case CMD_SET_HIGH_PERF_MODE:
1850                 case CMD_SET_COUNTRY_CODE:
1851                 case CMD_SET_FREQUENCY_BAND:
1852                 case CMD_START_PACKET_FILTERING:
1853                 case CMD_STOP_PACKET_FILTERING:
1854                     deferMessage(message);
1855                     break;
1856                 default:
1857                     return NOT_HANDLED;
1858             }
1859             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1860             return HANDLED;
1861         }
1862     }
1863
1864     class DriverLoadedState extends State {
1865         @Override
1866         public void enter() {
1867             if (DBG) Log.d(TAG, getName() + "\n");
1868             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1869         }
1870         @Override
1871         public boolean processMessage(Message message) {
1872             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1873             switch(message.what) {
1874                 case CMD_UNLOAD_DRIVER:
1875                     transitionTo(mDriverUnloadingState);
1876                     break;
1877                 case CMD_START_SUPPLICANT:
1878                     if(WifiNative.startSupplicant()) {
1879                         Log.d(TAG, "Supplicant start successful");
1880                         mWifiMonitor.startMonitoring();
1881                         transitionTo(mSupplicantStartingState);
1882                     } else {
1883                         Log.e(TAG, "Failed to start supplicant!");
1884                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
1885                     }
1886                     break;
1887                 case CMD_START_AP:
1888                     if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_STOPPED)) {
1889                         Log.d(TAG, "Soft AP start successful");
1890                         setWifiApState(WIFI_AP_STATE_ENABLED);
1891                         transitionTo(mSoftApStartedState);
1892                     } else {
1893                         Log.d(TAG, "Soft AP start failed");
1894                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
1895                     }
1896                     break;
1897                 default:
1898                     return NOT_HANDLED;
1899             }
1900             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1901             return HANDLED;
1902         }
1903     }
1904
1905     class DriverUnloadingState extends State {
1906         @Override
1907         public void enter() {
1908             if (DBG) Log.d(TAG, getName() + "\n");
1909             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1910
1911             final Message message = new Message();
1912             message.copyFrom(getCurrentMessage());
1913             new Thread(new Runnable() {
1914                 public void run() {
1915                     if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1916                     mWakeLock.acquire();
1917                     if(WifiNative.unloadDriver()) {
1918                         Log.d(TAG, "Driver unload successful");
1919                         sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
1920
1921                         switch(message.arg1) {
1922                             case WIFI_STATE_DISABLED:
1923                             case WIFI_STATE_UNKNOWN:
1924                                 setWifiState(message.arg1);
1925                                 break;
1926                             case WIFI_AP_STATE_DISABLED:
1927                             case WIFI_AP_STATE_FAILED:
1928                                 setWifiApState(message.arg1);
1929                                 break;
1930                         }
1931                     } else {
1932                         Log.e(TAG, "Failed to unload driver!");
1933                         sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
1934
1935                         switch(message.arg1) {
1936                             case WIFI_STATE_DISABLED:
1937                             case WIFI_STATE_UNKNOWN:
1938                                 setWifiState(WIFI_STATE_UNKNOWN);
1939                                 break;
1940                             case WIFI_AP_STATE_DISABLED:
1941                             case WIFI_AP_STATE_FAILED:
1942                                 setWifiApState(WIFI_AP_STATE_FAILED);
1943                                 break;
1944                         }
1945                     }
1946                     mWakeLock.release();
1947                 }
1948             }).start();
1949         }
1950
1951         @Override
1952         public boolean processMessage(Message message) {
1953             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1954             switch (message.what) {
1955                 case CMD_UNLOAD_DRIVER_SUCCESS:
1956                     transitionTo(mDriverUnloadedState);
1957                     break;
1958                 case CMD_UNLOAD_DRIVER_FAILURE:
1959                     transitionTo(mDriverFailedState);
1960                     break;
1961                 case CMD_LOAD_DRIVER:
1962                 case CMD_UNLOAD_DRIVER:
1963                 case CMD_START_SUPPLICANT:
1964                 case CMD_STOP_SUPPLICANT:
1965                 case CMD_START_AP:
1966                 case CMD_STOP_AP:
1967                 case CMD_START_DRIVER:
1968                 case CMD_STOP_DRIVER:
1969                 case CMD_SET_SCAN_MODE:
1970                 case CMD_SET_SCAN_TYPE:
1971                 case CMD_SET_HIGH_PERF_MODE:
1972                 case CMD_SET_COUNTRY_CODE:
1973                 case CMD_SET_FREQUENCY_BAND:
1974                 case CMD_START_PACKET_FILTERING:
1975                 case CMD_STOP_PACKET_FILTERING:
1976                     deferMessage(message);
1977                     break;
1978                 default:
1979                     return NOT_HANDLED;
1980             }
1981             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1982             return HANDLED;
1983         }
1984     }
1985
1986     class DriverUnloadedState extends State {
1987         @Override
1988         public void enter() {
1989             if (DBG) Log.d(TAG, getName() + "\n");
1990             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1991         }
1992         @Override
1993         public boolean processMessage(Message message) {
1994             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1995             switch (message.what) {
1996                 case CMD_LOAD_DRIVER:
1997                     transitionTo(mDriverLoadingState);
1998                     break;
1999                 default:
2000                     return NOT_HANDLED;
2001             }
2002             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2003             return HANDLED;
2004         }
2005     }
2006
2007     class DriverFailedState extends State {
2008         @Override
2009         public void enter() {
2010             Log.e(TAG, getName() + "\n");
2011             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2012         }
2013         @Override
2014         public boolean processMessage(Message message) {
2015             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2016             return NOT_HANDLED;
2017         }
2018     }
2019
2020
2021     class SupplicantStartingState extends State {
2022         @Override
2023         public void enter() {
2024             if (DBG) Log.d(TAG, getName() + "\n");
2025             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2026         }
2027         @Override
2028         public boolean processMessage(Message message) {
2029             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2030             switch(message.what) {
2031                 case SUP_CONNECTION_EVENT:
2032                     Log.d(TAG, "Supplicant connection established");
2033                     setWifiState(WIFI_STATE_ENABLED);
2034                     mSupplicantRestartCount = 0;
2035                     /* Reset the supplicant state to indicate the supplicant
2036                      * state is not known at this time */
2037                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2038                     mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2039                     /* Initialize data structures */
2040                     mLastBssid = null;
2041                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2042                     mLastSignalLevel = -1;
2043
2044                     mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
2045
2046                     WifiConfigStore.initialize(mContext);
2047
2048                     //TODO: initialize and fix multicast filtering
2049                     //mWM.initializeMulticastFiltering();
2050
2051                     sendSupplicantConnectionChangedBroadcast(true);
2052                     transitionTo(mDriverStartedState);
2053                     break;
2054                 case SUP_DISCONNECTION_EVENT:
2055                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2056                         Log.e(TAG, "Failed to setup control channel, restart supplicant");
2057                         WifiNative.killSupplicant();
2058                         transitionTo(mDriverLoadedState);
2059                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2060                     } else {
2061                         mSupplicantRestartCount = 0;
2062                         Log.e(TAG, "Failed " + mSupplicantRestartCount +
2063                                 " times to start supplicant, unload driver");
2064                         transitionTo(mDriverLoadedState);
2065                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2066                     }
2067                     break;
2068                 case CMD_LOAD_DRIVER:
2069                 case CMD_UNLOAD_DRIVER:
2070                 case CMD_START_SUPPLICANT:
2071                 case CMD_STOP_SUPPLICANT:
2072                 case CMD_START_AP:
2073                 case CMD_STOP_AP:
2074                 case CMD_START_DRIVER:
2075                 case CMD_STOP_DRIVER:
2076                 case CMD_SET_SCAN_MODE:
2077                 case CMD_SET_SCAN_TYPE:
2078                 case CMD_SET_HIGH_PERF_MODE:
2079                 case CMD_SET_COUNTRY_CODE:
2080                 case CMD_SET_FREQUENCY_BAND:
2081                 case CMD_START_PACKET_FILTERING:
2082                 case CMD_STOP_PACKET_FILTERING:
2083                     deferMessage(message);
2084                     break;
2085                 default:
2086                     return NOT_HANDLED;
2087             }
2088             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2089             return HANDLED;
2090         }
2091     }
2092
2093     class SupplicantStartedState extends State {
2094         @Override
2095         public void enter() {
2096             if (DBG) Log.d(TAG, getName() + "\n");
2097             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2098             /* Initialize for connect mode operation at start */
2099             mIsScanMode = false;
2100             /* Wifi is available as long as we have a connection to supplicant */
2101             mNetworkInfo.setIsAvailable(true);
2102         }
2103         @Override
2104         public boolean processMessage(Message message) {
2105             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2106             WifiConfiguration config;
2107             boolean eventLoggingEnabled = true;
2108             switch(message.what) {
2109                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
2110                     Log.d(TAG, "stopping supplicant");
2111                     if (!WifiNative.stopSupplicant()) {
2112                         Log.e(TAG, "Failed to stop supplicant, issue kill");
2113                         WifiNative.killSupplicant();
2114                     }
2115                     mNetworkInfo.setIsAvailable(false);
2116                     handleNetworkDisconnect();
2117                     setWifiState(WIFI_STATE_DISABLING);
2118                     sendSupplicantConnectionChangedBroadcast(false);
2119                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2120                     mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2121                     transitionTo(mSupplicantStoppingState);
2122                     break;
2123                 case SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
2124                     Log.e(TAG, "Connection lost, restart supplicant");
2125                     WifiNative.killSupplicant();
2126                     WifiNative.closeSupplicantConnection();
2127                     mNetworkInfo.setIsAvailable(false);
2128                     handleNetworkDisconnect();
2129                     sendSupplicantConnectionChangedBroadcast(false);
2130                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2131                     mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2132                     transitionTo(mDriverLoadedState);
2133                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2134                     break;
2135                 case SCAN_RESULTS_EVENT:
2136                     eventLoggingEnabled = false;
2137                     setScanResults(WifiNative.scanResultsCommand());
2138                     sendScanResultsAvailableBroadcast();
2139                     mScanResultIsPending = false;
2140                     break;
2141                 case CMD_PING_SUPPLICANT:
2142                     boolean ok = WifiNative.pingCommand();
2143                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2144                     break;
2145                 case CMD_ADD_OR_UPDATE_NETWORK:
2146                     config = (WifiConfiguration) message.obj;
2147                     mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2148                             WifiConfigStore.addOrUpdateNetwork(config));
2149                     break;
2150                 case CMD_REMOVE_NETWORK:
2151                     ok = WifiConfigStore.removeNetwork(message.arg1);
2152                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2153                     break;
2154                 case CMD_ENABLE_NETWORK:
2155                     ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2156                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2157                     break;
2158                 case CMD_ENABLE_ALL_NETWORKS:
2159                     WifiConfigStore.enableAllNetworks();
2160                     break;
2161                 case CMD_DISABLE_NETWORK:
2162                     ok = WifiConfigStore.disableNetwork(message.arg1);
2163                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2164                     break;
2165                 case CMD_BLACKLIST_NETWORK:
2166                     WifiNative.addToBlacklistCommand((String)message.obj);
2167                     break;
2168                 case CMD_CLEAR_BLACKLIST:
2169                     WifiNative.clearBlacklistCommand();
2170                     break;
2171                 case CMD_SAVE_CONFIG:
2172                     ok = WifiConfigStore.saveConfig();
2173                     mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2174
2175                     // Inform the backup manager about a data change
2176                     IBackupManager ibm = IBackupManager.Stub.asInterface(
2177                             ServiceManager.getService(Context.BACKUP_SERVICE));
2178                     if (ibm != null) {
2179                         try {
2180                             ibm.dataChanged("com.android.providers.settings");
2181                         } catch (Exception e) {
2182                             // Try again later
2183                         }
2184                     }
2185                     break;
2186                     /* Cannot start soft AP while in client mode */
2187                 case CMD_START_AP:
2188                     Log.d(TAG, "Failed to start soft AP with a running supplicant");
2189                     setWifiApState(WIFI_AP_STATE_FAILED);
2190                     break;
2191                 case CMD_SET_SCAN_MODE:
2192                     mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2193                     break;
2194                 case CMD_SAVE_NETWORK:
2195                     config = (WifiConfiguration) message.obj;
2196                     WifiConfigStore.saveNetwork(config);
2197                     break;
2198                 case CMD_FORGET_NETWORK:
2199                     WifiConfigStore.forgetNetwork(message.arg1);
2200                     break;
2201                 default:
2202                     return NOT_HANDLED;
2203             }
2204             if (eventLoggingEnabled) {
2205                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2206             }
2207             return HANDLED;
2208         }
2209
2210         @Override
2211         public void exit() {
2212             mNetworkInfo.setIsAvailable(false);
2213         }
2214     }
2215
2216     class SupplicantStoppingState extends State {
2217         @Override
2218         public void enter() {
2219             if (DBG) Log.d(TAG, getName() + "\n");
2220             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2221         }
2222         @Override
2223         public boolean processMessage(Message message) {
2224             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2225             switch(message.what) {
2226                 case SUP_CONNECTION_EVENT:
2227                     Log.e(TAG, "Supplicant connection received while stopping");
2228                     break;
2229                 case SUP_DISCONNECTION_EVENT:
2230                     Log.d(TAG, "Supplicant connection lost");
2231                     WifiNative.closeSupplicantConnection();
2232                     transitionTo(mDriverLoadedState);
2233                     break;
2234                 case CMD_LOAD_DRIVER:
2235                 case CMD_UNLOAD_DRIVER:
2236                 case CMD_START_SUPPLICANT:
2237                 case CMD_STOP_SUPPLICANT:
2238                 case CMD_START_AP:
2239                 case CMD_STOP_AP:
2240                 case CMD_START_DRIVER:
2241                 case CMD_STOP_DRIVER:
2242                 case CMD_SET_SCAN_MODE:
2243                 case CMD_SET_SCAN_TYPE:
2244                 case CMD_SET_HIGH_PERF_MODE:
2245                 case CMD_SET_COUNTRY_CODE:
2246                 case CMD_SET_FREQUENCY_BAND:
2247                 case CMD_START_PACKET_FILTERING:
2248                 case CMD_STOP_PACKET_FILTERING:
2249                     deferMessage(message);
2250                     break;
2251                 default:
2252                     return NOT_HANDLED;
2253             }
2254             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2255             return HANDLED;
2256         }
2257     }
2258
2259     class DriverStartingState extends State {
2260         @Override
2261         public void enter() {
2262             if (DBG) Log.d(TAG, getName() + "\n");
2263             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2264         }
2265         @Override
2266         public boolean processMessage(Message message) {
2267             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2268             switch(message.what) {
2269                 case DRIVER_START_EVENT:
2270                     transitionTo(mDriverStartedState);
2271                     break;
2272                     /* Queue driver commands & connection events */
2273                 case CMD_START_DRIVER:
2274                 case CMD_STOP_DRIVER:
2275                 case SUPPLICANT_STATE_CHANGE_EVENT:
2276                 case NETWORK_CONNECTION_EVENT:
2277                 case NETWORK_DISCONNECTION_EVENT:
2278                 case AUTHENTICATION_FAILURE_EVENT:
2279                 case WPS_OVERLAP_EVENT:
2280                 case CMD_SET_SCAN_TYPE:
2281                 case CMD_SET_HIGH_PERF_MODE:
2282                 case CMD_SET_COUNTRY_CODE:
2283                 case CMD_SET_FREQUENCY_BAND:
2284                 case CMD_START_PACKET_FILTERING:
2285                 case CMD_STOP_PACKET_FILTERING:
2286                 case CMD_START_SCAN:
2287                 case CMD_DISCONNECT:
2288                 case CMD_REASSOCIATE:
2289                 case CMD_RECONNECT:
2290                     deferMessage(message);
2291                     break;
2292                 default:
2293                     return NOT_HANDLED;
2294             }
2295             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2296             return HANDLED;
2297         }
2298     }
2299
2300     class DriverStartedState extends State {
2301         @Override
2302         public void enter() {
2303             if (DBG) Log.d(TAG, getName() + "\n");
2304             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2305
2306             mIsRunning = true;
2307             updateBatteryWorkSource(null);
2308
2309             /**
2310              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2311              * When this mode is on, some of the low-level scan parameters used by the
2312              * driver are changed to reduce interference with bluetooth
2313              */
2314             WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2315             /* set country code */
2316             setCountryCode();
2317             /* set frequency band of operation */
2318             setFrequencyBand();
2319             /* initialize network state */
2320             setNetworkDetailedState(DetailedState.DISCONNECTED);
2321
2322             if (mIsScanMode) {
2323                 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2324                 WifiNative.disconnectCommand();
2325                 transitionTo(mScanModeState);
2326             } else {
2327                 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2328                 WifiNative.reconnectCommand();
2329                 transitionTo(mDisconnectedState);
2330             }
2331         }
2332         @Override
2333         public boolean processMessage(Message message) {
2334             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2335             boolean eventLoggingEnabled = true;
2336             switch(message.what) {
2337                 case CMD_SET_SCAN_TYPE:
2338                     if (message.arg1 == SCAN_ACTIVE) {
2339                         WifiNative.setScanModeCommand(true);
2340                     } else {
2341                         WifiNative.setScanModeCommand(false);
2342                     }
2343                     break;
2344                 case CMD_START_SCAN:
2345                     eventLoggingEnabled = false;
2346                     WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
2347                     mScanResultIsPending = true;
2348                     break;
2349                 case CMD_SET_HIGH_PERF_MODE:
2350                     setHighPerfModeEnabledNative(message.arg1 == 1);
2351                     break;
2352                 case CMD_SET_COUNTRY_CODE:
2353                     String country = (String) message.obj;
2354                     Log.d(TAG, "set country code " + country);
2355                     if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) {
2356                         Log.e(TAG, "Failed to set country code " + country);
2357                     }
2358                     break;
2359                 case CMD_SET_FREQUENCY_BAND:
2360                     int band =  message.arg1;
2361                     Log.d(TAG, "set frequency band " + band);
2362                     if (WifiNative.setBandCommand(band)) {
2363                         mFrequencyBand.set(band);
2364                         //Fetch the latest scan results when frequency band is set
2365                         startScan(true);
2366                     } else {
2367                         Log.e(TAG, "Failed to set frequency band " + band);
2368                     }
2369                     break;
2370                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2371                     mBluetoothConnectionActive = (message.arg1 !=
2372                             BluetoothAdapter.STATE_DISCONNECTED);
2373                     WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2374                     break;
2375                 case CMD_STOP_DRIVER:
2376                     mWakeLock.acquire();
2377                     WifiNative.stopDriverCommand();
2378                     transitionTo(mDriverStoppingState);
2379                     mWakeLock.release();
2380                     break;
2381                 case CMD_START_PACKET_FILTERING:
2382                     WifiNative.startPacketFiltering();
2383                     break;
2384                 case CMD_STOP_PACKET_FILTERING:
2385                     WifiNative.stopPacketFiltering();
2386                     break;
2387                 default:
2388                     return NOT_HANDLED;
2389             }
2390             if (eventLoggingEnabled) {
2391                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2392             }
2393             return HANDLED;
2394         }
2395         @Override
2396         public void exit() {
2397             if (DBG) Log.d(TAG, getName() + "\n");
2398             mIsRunning = false;
2399             updateBatteryWorkSource(null);
2400             mScanResults = null;
2401         }
2402     }
2403
2404     class DriverStoppingState extends State {
2405         @Override
2406         public void enter() {
2407             if (DBG) Log.d(TAG, getName() + "\n");
2408             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2409         }
2410         @Override
2411         public boolean processMessage(Message message) {
2412             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2413             switch(message.what) {
2414                 case DRIVER_STOP_EVENT:
2415                     transitionTo(mDriverStoppedState);
2416                     break;
2417                     /* Queue driver commands */
2418                 case CMD_START_DRIVER:
2419                 case CMD_STOP_DRIVER:
2420                 case CMD_SET_SCAN_TYPE:
2421                 case CMD_SET_HIGH_PERF_MODE:
2422                 case CMD_SET_COUNTRY_CODE:
2423                 case CMD_SET_FREQUENCY_BAND:
2424                 case CMD_START_PACKET_FILTERING:
2425                 case CMD_STOP_PACKET_FILTERING:
2426                 case CMD_START_SCAN:
2427                 case CMD_DISCONNECT:
2428                 case CMD_REASSOCIATE:
2429                 case CMD_RECONNECT:
2430                     deferMessage(message);
2431                     break;
2432                 default:
2433                     return NOT_HANDLED;
2434             }
2435             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2436             return HANDLED;
2437         }
2438     }
2439
2440     class DriverStoppedState extends State {
2441         @Override
2442         public void enter() {
2443             if (DBG) Log.d(TAG, getName() + "\n");
2444             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2445         }
2446         @Override
2447         public boolean processMessage(Message message) {
2448             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2449             switch (message.what) {
2450                 case CMD_START_DRIVER:
2451                     mWakeLock.acquire();
2452                     WifiNative.startDriverCommand();
2453                     transitionTo(mDriverStartingState);
2454                     mWakeLock.release();
2455                     break;
2456                 default:
2457                     return NOT_HANDLED;
2458             }
2459             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2460             return HANDLED;
2461         }
2462     }
2463
2464     class ScanModeState extends State {
2465         @Override
2466         public void enter() {
2467             if (DBG) Log.d(TAG, getName() + "\n");
2468             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2469         }
2470         @Override
2471         public boolean processMessage(Message message) {
2472             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2473             switch(message.what) {
2474                 case CMD_SET_SCAN_MODE:
2475                     if (message.arg1 == SCAN_ONLY_MODE) {
2476                         /* Ignore */
2477                         return HANDLED;
2478                     } else {
2479                         WifiNative.setScanResultHandlingCommand(message.arg1);
2480                         WifiNative.reconnectCommand();
2481                         mIsScanMode = false;
2482                         transitionTo(mDisconnectedState);
2483                     }
2484                     break;
2485                     /* Ignore */
2486                 case CMD_DISCONNECT:
2487                 case CMD_RECONNECT:
2488                 case CMD_REASSOCIATE:
2489                 case SUPPLICANT_STATE_CHANGE_EVENT:
2490                 case NETWORK_CONNECTION_EVENT:
2491                 case NETWORK_DISCONNECTION_EVENT:
2492                     break;
2493                 default:
2494                     return NOT_HANDLED;
2495             }
2496             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2497             return HANDLED;
2498         }
2499     }
2500
2501     class ConnectModeState extends State {
2502         @Override
2503         public void enter() {
2504             if (DBG) Log.d(TAG, getName() + "\n");
2505             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2506         }
2507         @Override
2508         public boolean processMessage(Message message) {
2509             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2510             StateChangeResult stateChangeResult;
2511             switch(message.what) {
2512                 case AUTHENTICATION_FAILURE_EVENT:
2513                     mSupplicantStateTracker.sendMessage(AUTHENTICATION_FAILURE_EVENT);
2514                     break;
2515                 case WPS_OVERLAP_EVENT:
2516                     /* We just need to broadcast the error */
2517                     sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
2518                     break;
2519                 case SUPPLICANT_STATE_CHANGE_EVENT:
2520                     stateChangeResult = (StateChangeResult) message.obj;
2521                     SupplicantState state = stateChangeResult.state;
2522                     // Supplicant state change
2523                     // [31-13] Reserved for future use
2524                     // [8 - 0] Supplicant state (as defined in SupplicantState.java)
2525                     // 50023 supplicant_state_changed (custom|1|5)
2526                     EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
2527                     mWifiInfo.setSupplicantState(state);
2528                     // Network id is only valid when we start connecting
2529                     if (SupplicantState.isConnecting(state)) {
2530                         mWifiInfo.setNetworkId(stateChangeResult.networkId);
2531                     } else {
2532                         mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2533                     }
2534
2535                     if (state == SupplicantState.ASSOCIATING) {
2536                         /* BSSID is valid only in ASSOCIATING state */
2537                         mWifiInfo.setBSSID(stateChangeResult.BSSID);
2538                     }
2539
2540                     mSupplicantStateTracker.sendMessage(Message.obtain(message));
2541                     mWpsStateMachine.sendMessage(Message.obtain(message));
2542                     break;
2543                     /* Do a redundant disconnect without transition */
2544                 case CMD_DISCONNECT:
2545                     WifiNative.disconnectCommand();
2546                     break;
2547                 case CMD_RECONNECT:
2548                     WifiNative.reconnectCommand();
2549                     break;
2550                 case CMD_REASSOCIATE:
2551                     WifiNative.reassociateCommand();
2552                     break;
2553                 case CMD_CONNECT_NETWORK:
2554                     int netId = message.arg1;
2555                     WifiConfiguration config = (WifiConfiguration) message.obj;
2556
2557                     /* We connect to a specific network by issuing a select
2558                      * to the WifiConfigStore. This enables the network,
2559                      * while disabling all other networks in the supplicant.
2560                      * Disabling a connected network will cause a disconnection
2561                      * from the network. A reconnectCommand() will then initiate
2562                      * a connection to the enabled network.
2563                      */
2564                     if (config != null) {
2565                         WifiConfigStore.selectNetwork(config);
2566                     } else {
2567                         WifiConfigStore.selectNetwork(netId);
2568                     }
2569
2570                     /* The state tracker handles enabling networks upon completion/failure */
2571                     mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
2572
2573                     WifiNative.reconnectCommand();
2574
2575                     /* Expect a disconnection from the old connection */
2576                     transitionTo(mDisconnectingState);
2577                     break;
2578                 case CMD_START_WPS:
2579                     mWpsStateMachine.sendMessage(Message.obtain(message));
2580                     transitionTo(mWaitForWpsCompletionState);
2581                     break;
2582                 case SCAN_RESULTS_EVENT:
2583                     /* Set the scan setting back to "connect" mode */
2584                     WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2585                     /* Handle scan results */
2586                     return NOT_HANDLED;
2587                 case NETWORK_CONNECTION_EVENT:
2588                     Log.d(TAG,"Network connection established");
2589                     mLastNetworkId = message.arg1;
2590                     mLastBssid = (String) message.obj;
2591
2592                     //TODO: make supplicant modification to push this in events
2593                     mWifiInfo.setSSID(fetchSSID());
2594                     mWifiInfo.setBSSID(mLastBssid);
2595                     mWifiInfo.setNetworkId(mLastNetworkId);
2596                     /* send event to CM & network change broadcast */
2597                     setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
2598                     sendNetworkStateChangeBroadcast(mLastBssid);
2599                     transitionTo(mConnectingState);
2600                     break;
2601                 case NETWORK_DISCONNECTION_EVENT:
2602                     Log.d(TAG,"Network connection lost");
2603                     handleNetworkDisconnect();
2604                     transitionTo(mDisconnectedState);
2605                     break;
2606                 default:
2607                     return NOT_HANDLED;
2608             }
2609             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2610             return HANDLED;
2611         }
2612     }
2613
2614     class ConnectingState extends State {
2615
2616         @Override
2617         public void enter() {
2618             if (DBG) Log.d(TAG, getName() + "\n");
2619             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2620
2621              if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
2622                 //start DHCP
2623                 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
2624                         mContext, WifiStateMachine.this, mInterfaceName);
2625                 mDhcpStateMachine.registerForPreDhcpNotification();
2626                 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
2627             } else {
2628                 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
2629                         mLastNetworkId);
2630                 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
2631                 INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b);
2632                 InterfaceConfiguration ifcg = new InterfaceConfiguration();
2633                 ifcg.addr = dhcpInfoInternal.makeLinkAddress();
2634                 ifcg.interfaceFlags = "[up]";
2635                 try {
2636                     netd.setInterfaceConfig(mInterfaceName, ifcg);
2637                     Log.v(TAG, "Static IP configuration succeeded");
2638                     sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
2639                 } catch (RemoteException re) {
2640                     Log.v(TAG, "Static IP configuration failed: " + re);
2641                     sendMessage(CMD_STATIC_IP_FAILURE);
2642                 } catch (IllegalStateException e) {
2643                     Log.v(TAG, "Static IP configuration failed: " + e);
2644                     sendMessage(CMD_STATIC_IP_FAILURE);
2645                 }
2646             }
2647          }
2648       @Override
2649       public boolean processMessage(Message message) {
2650           if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2651
2652           switch(message.what) {
2653               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2654                   handlePreDhcpSetup();
2655                   mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2656                   break;
2657               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2658                   handlePostDhcpSetup();
2659                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2660                       handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2661                       transitionTo(mConnectedState);
2662                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2663                       handleFailedIpConfiguration();
2664                       transitionTo(mDisconnectingState);
2665                   }
2666                   break;
2667               case CMD_STATIC_IP_SUCCESS:
2668                   handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2669                   transitionTo(mConnectedState);
2670                   break;
2671               case CMD_STATIC_IP_FAILURE:
2672                   handleFailedIpConfiguration();
2673                   transitionTo(mDisconnectingState);
2674                   break;
2675               case CMD_DISCONNECT:
2676                   WifiNative.disconnectCommand();
2677                   transitionTo(mDisconnectingState);
2678                   break;
2679                   /* Ignore connection to same network */
2680               case CMD_CONNECT_NETWORK:
2681                   int netId = message.arg1;
2682                   if (mWifiInfo.getNetworkId() == netId) {
2683                       break;
2684                   }
2685                   return NOT_HANDLED;
2686               case CMD_SAVE_NETWORK:
2687                   deferMessage(message);
2688                   break;
2689                   /* Ignore */
2690               case NETWORK_CONNECTION_EVENT:
2691                   break;
2692               case CMD_STOP_DRIVER:
2693                   sendMessage(CMD_DISCONNECT);
2694                   deferMessage(message);
2695                   break;
2696               case CMD_SET_SCAN_MODE:
2697                   if (message.arg1 == SCAN_ONLY_MODE) {
2698                       sendMessage(CMD_DISCONNECT);
2699                       deferMessage(message);
2700                   }
2701                   break;
2702                   /* Defer scan when IP is being fetched */
2703               case CMD_START_SCAN:
2704                   deferMessage(message);
2705                   break;
2706                   /* Defer any power mode changes since we must keep active power mode at DHCP */
2707               case CMD_SET_HIGH_PERF_MODE:
2708                   deferMessage(message);
2709                   break;
2710               default:
2711                 return NOT_HANDLED;
2712           }
2713           EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2714           return HANDLED;
2715       }
2716     }
2717
2718     class ConnectedState extends State {
2719         @Override
2720         public void enter() {
2721             if (DBG) Log.d(TAG, getName() + "\n");
2722             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2723             mRssiPollToken++;
2724             if (mEnableRssiPolling) {
2725                 sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0));
2726             }
2727         }
2728         @Override
2729         public boolean processMessage(Message message) {
2730             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2731             boolean eventLoggingEnabled = true;
2732             switch (message.what) {
2733               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2734                   handlePreDhcpSetup();
2735                   mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2736                   break;
2737               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2738                   handlePostDhcpSetup();
2739                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2740                       handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2741                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2742                       handleFailedIpConfiguration();
2743                       transitionTo(mDisconnectingState);
2744                   }
2745                   break;
2746                 case CMD_DISCONNECT:
2747                     WifiNative.disconnectCommand();
2748                     transitionTo(mDisconnectingState);
2749                     break;
2750                 case CMD_STOP_DRIVER:
2751                     sendMessage(CMD_DISCONNECT);
2752                     deferMessage(message);
2753                     break;
2754                 case CMD_REQUEST_CM_WAKELOCK:
2755                     if (mCm == null) {
2756                         mCm = (ConnectivityManager)mContext.getSystemService(
2757                                 Context.CONNECTIVITY_SERVICE);
2758                     }
2759                     mCm.requestNetworkTransitionWakelock(TAG);
2760                     break;
2761                 case CMD_SET_SCAN_MODE:
2762                     if (message.arg1 == SCAN_ONLY_MODE) {
2763                         sendMessage(CMD_DISCONNECT);
2764                         deferMessage(message);
2765                     }
2766                     break;
2767                 case CMD_START_SCAN:
2768                     eventLoggingEnabled = false;
2769                     /* When the network is connected, re-scanning can trigger
2770                      * a reconnection. Put it in scan-only mode during scan.
2771                      * When scan results are received, the mode is switched
2772                      * back to CONNECT_MODE.
2773                      */
2774                     WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2775                     /* Have the parent state handle the rest */
2776                     return NOT_HANDLED;
2777                     /* Ignore connection to same network */
2778                 case CMD_CONNECT_NETWORK:
2779                     int netId = message.arg1;
2780                     if (mWifiInfo.getNetworkId() == netId) {
2781                         break;
2782                     }
2783                     return NOT_HANDLED;
2784                 case CMD_SAVE_NETWORK:
2785                     WifiConfiguration config = (WifiConfiguration) message.obj;
2786                     NetworkUpdateResult result = WifiConfigStore.saveNetwork(config);
2787                     if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
2788                         if (result.hasIpChanged()) {
2789                             Log.d(TAG,"Reconfiguring IP on connection");
2790                             transitionTo(mConnectingState);
2791                         }
2792                         if (result.hasProxyChanged()) {
2793                             Log.d(TAG,"Reconfiguring proxy on connection");
2794                             configureLinkProperties();
2795                             sendLinkConfigurationChangedBroadcast();
2796                         }
2797                     }
2798                     break;
2799                     /* Ignore */
2800                 case NETWORK_CONNECTION_EVENT:
2801                     break;
2802                 case CMD_RSSI_POLL:
2803                     eventLoggingEnabled = false;
2804                     if (message.arg1 == mRssiPollToken) {
2805                         // Get Info and continue polling
2806                         fetchRssiAndLinkSpeedNative();
2807                         sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2808                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2809                     } else {
2810                         // Polling has completed
2811                     }
2812                     break;
2813                 case CMD_ENABLE_RSSI_POLL:
2814                     mEnableRssiPolling = (message.arg1 == 1);
2815                     mRssiPollToken++;
2816                     if (mEnableRssiPolling) {
2817                         // first poll
2818                         fetchRssiAndLinkSpeedNative();
2819                         sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2820                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2821                     }
2822                     break;
2823                 default:
2824                     return NOT_HANDLED;
2825             }
2826             if (eventLoggingEnabled) {
2827                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2828             }
2829             return HANDLED;
2830         }
2831         @Override
2832         public void exit() {
2833             /* If a scan result is pending in connected state, the supplicant
2834              * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
2835              */
2836             if (mScanResultIsPending) {
2837                 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2838             }
2839         }
2840     }
2841
2842     class DisconnectingState extends State {
2843         @Override
2844         public void enter() {
2845             if (DBG) Log.d(TAG, getName() + "\n");
2846             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2847         }
2848         @Override
2849         public boolean processMessage(Message message) {
2850             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2851             switch (message.what) {
2852                 case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
2853                     deferMessage(message);
2854                     break;
2855                 case CMD_SET_SCAN_MODE:
2856                     if (message.arg1 == SCAN_ONLY_MODE) {
2857                         deferMessage(message);
2858                     }
2859                     break;
2860                     /* Handle in  DisconnectedState */
2861                 case SUPPLICANT_STATE_CHANGE_EVENT:
2862                     deferMessage(message);
2863                     break;
2864                 default:
2865                     return NOT_HANDLED;
2866             }
2867             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2868             return HANDLED;
2869         }
2870     }
2871
2872     class DisconnectedState extends State {
2873         private boolean mAlarmEnabled = false;
2874         private long mScanIntervalMs;
2875
2876         private void setScanAlarm(boolean enabled) {
2877             if (enabled == mAlarmEnabled) return;
2878             if (enabled) {
2879                 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
2880                         System.currentTimeMillis() + mScanIntervalMs,
2881                         mScanIntervalMs,
2882                         mScanIntent);
2883
2884                 mAlarmEnabled = true;
2885             } else {
2886                 mAlarmManager.cancel(mScanIntent);
2887                 mAlarmEnabled = false;
2888             }
2889         }
2890
2891         @Override
2892         public void enter() {
2893             if (DBG) Log.d(TAG, getName() + "\n");
2894             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2895
2896             mScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2897                     Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
2898             /*
2899              * We initiate background scanning if it is enabled, otherwise we
2900              * initiate an infrequent scan that wakes up the device to ensure
2901              * a user connects to an access point on the move
2902              */
2903             if (mEnableBackgroundScan) {
2904                 /* If a regular scan result is pending, do not initiate background
2905                  * scan until the scan results are returned. This is needed because
2906                  * initiating a background scan will cancel the regular scan and
2907                  * scan results will not be returned until background scanning is
2908                  * cleared
2909                  */
2910                 if (!mScanResultIsPending) {
2911                     WifiNative.enableBackgroundScan(true);
2912                 }
2913             } else {
2914                 setScanAlarm(true);
2915             }
2916         }
2917         @Override
2918         public boolean processMessage(Message message) {
2919             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2920             switch (message.what) {
2921                 case CMD_SET_SCAN_MODE:
2922                     if (message.arg1 == SCAN_ONLY_MODE) {
2923                         WifiNative.setScanResultHandlingCommand(message.arg1);
2924                         //Supplicant disconnect to prevent further connects
2925                         WifiNative.disconnectCommand();
2926                         mIsScanMode = true;
2927                         transitionTo(mScanModeState);
2928                     }
2929                     break;
2930                 case CMD_ENABLE_BACKGROUND_SCAN:
2931                     mEnableBackgroundScan = (message.arg1 == 1);
2932                     if (mEnableBackgroundScan) {
2933                         WifiNative.enableBackgroundScan(true);
2934                         setScanAlarm(false);
2935                     } else {
2936                         WifiNative.enableBackgroundScan(false);
2937                         setScanAlarm(true);
2938                     }
2939                     break;
2940                     /* Ignore network disconnect */
2941                 case NETWORK_DISCONNECTION_EVENT:
2942                     break;
2943                 case SUPPLICANT_STATE_CHANGE_EVENT:
2944                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2945                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
2946                     /* DriverStartedState does the rest of the handling */
2947                     return NOT_HANDLED;
2948                 case CMD_START_SCAN:
2949                     /* Disable background scan temporarily during a regular scan */
2950                     if (mEnableBackgroundScan) {
2951                         WifiNative.enableBackgroundScan(false);
2952                     }
2953                     /* Handled in parent state */
2954                     return NOT_HANDLED;
2955                 case SCAN_RESULTS_EVENT:
2956                     /* Re-enable background scan when a pending scan result is received */
2957                     if (mEnableBackgroundScan && mScanResultIsPending) {
2958                         WifiNative.enableBackgroundScan(true);
2959                     }
2960                     /* Handled in parent state */
2961                     return NOT_HANDLED;
2962                 default:
2963                     return NOT_HANDLED;
2964             }
2965             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2966             return HANDLED;
2967         }
2968
2969         @Override
2970         public void exit() {
2971             /* No need for a background scan upon exit from a disconnected state */
2972             if (mEnableBackgroundScan) {
2973                 WifiNative.enableBackgroundScan(false);
2974             }
2975             setScanAlarm(false);
2976         }
2977     }
2978
2979     class WaitForWpsCompletionState extends State {
2980         @Override
2981         public void enter() {
2982             if (DBG) Log.d(TAG, getName() + "\n");
2983             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2984         }
2985         @Override
2986         public boolean processMessage(Message message) {
2987             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2988             switch (message.what) {
2989                 /* Defer all commands that can cause connections to a different network
2990                  * or put the state machine out of connect mode
2991                  */
2992                 case CMD_STOP_DRIVER:
2993                 case CMD_SET_SCAN_MODE:
2994                 case CMD_CONNECT_NETWORK:
2995                 case CMD_ENABLE_NETWORK:
2996                 case CMD_RECONNECT:
2997                 case CMD_REASSOCIATE:
2998                 case NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */
2999                     deferMessage(message);
3000                     break;
3001                 case NETWORK_DISCONNECTION_EVENT:
3002                     Log.d(TAG,"Network connection lost");
3003                     handleNetworkDisconnect();
3004                     break;
3005                 case WPS_COMPLETED_EVENT:
3006                     /* we are still disconnected until we see a network connection
3007                      * notification */
3008                     transitionTo(mDisconnectedState);
3009                     break;
3010                 default:
3011                     return NOT_HANDLED;
3012             }
3013             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3014             return HANDLED;
3015         }
3016     }
3017
3018     class SoftApStartedState extends State {
3019         @Override
3020         public void enter() {
3021             if (DBG) Log.d(TAG, getName() + "\n");
3022             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3023         }
3024         @Override
3025         public boolean processMessage(Message message) {
3026             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3027             switch(message.what) {
3028                 case CMD_STOP_AP:
3029                     Log.d(TAG,"Stopping Soft AP");
3030                     setWifiApState(WIFI_AP_STATE_DISABLING);
3031
3032                     if (mCm == null) {
3033                         mCm = (ConnectivityManager) mContext.getSystemService(
3034                                 Context.CONNECTIVITY_SERVICE);
3035                     }
3036                     if (mCm.untether(SOFTAP_IFACE) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
3037                         Log.e(TAG, "Untether initiate failed!");
3038                     }
3039                     try {
3040                         nwService.stopAccessPoint();
3041                     } catch(Exception e) {
3042                         Log.e(TAG, "Exception in stopAccessPoint()");
3043                     }
3044                     transitionTo(mDriverLoadedState);
3045                     break;
3046                 case CMD_START_AP:
3047                     Log.d(TAG,"SoftAP set on a running access point");
3048                     if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_RUNNING)) {
3049                         Log.d(TAG, "Soft AP start successful");
3050                         setWifiApState(WIFI_AP_STATE_ENABLED);
3051                         transitionTo(mSoftApStartedState);
3052                     } else {
3053                         Log.d(TAG, "Soft AP start failed");
3054                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
3055                     }
3056                     break;
3057                 /* Fail client mode operation when soft AP is enabled */
3058                 case CMD_START_SUPPLICANT:
3059                     Log.e(TAG,"Cannot start supplicant with a running soft AP");
3060                     setWifiState(WIFI_STATE_UNKNOWN);
3061                     break;
3062                 default:
3063                     return NOT_HANDLED;
3064             }
3065             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3066             return HANDLED;
3067         }
3068     }
3069 }