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