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