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