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