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