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