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