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