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