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