WifiStateMachine.java revision 06c43d575c88976f8709ff3fc0bad7117bde23e7
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        synchronized (mScanResultCache) {
895            List<ScanResult> scanList = new ArrayList<ScanResult>();
896            for(ScanResult result: mScanResults) {
897                scanList.add(new ScanResult(result));
898            }
899            return scanList;
900        }
901    }
902
903    /**
904     * Disconnect from Access Point
905     */
906    public void disconnectCommand() {
907        sendMessage(CMD_DISCONNECT);
908    }
909
910    /**
911     * Initiate a reconnection to AP
912     */
913    public void reconnectCommand() {
914        sendMessage(CMD_RECONNECT);
915    }
916
917    /**
918     * Initiate a re-association to AP
919     */
920    public void reassociateCommand() {
921        sendMessage(CMD_REASSOCIATE);
922    }
923
924    /**
925     * Add a network synchronously
926     *
927     * @return network id of the new network
928     */
929    public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
930        Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
931        int result = resultMsg.arg1;
932        resultMsg.recycle();
933        return result;
934    }
935
936    public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) {
937        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS);
938        List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
939        resultMsg.recycle();
940        return result;
941    }
942
943    /**
944     * Delete a network
945     *
946     * @param networkId id of the network to be removed
947     */
948    public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
949        Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
950        boolean result = (resultMsg.arg1 != FAILURE);
951        resultMsg.recycle();
952        return result;
953    }
954
955    /**
956     * Enable a network
957     *
958     * @param netId network id of the network
959     * @param disableOthers true, if all other networks have to be disabled
960     * @return {@code true} if the operation succeeds, {@code false} otherwise
961     */
962    public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
963        Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
964                disableOthers ? 1 : 0);
965        boolean result = (resultMsg.arg1 != FAILURE);
966        resultMsg.recycle();
967        return result;
968    }
969
970    /**
971     * Disable a network
972     *
973     * @param netId network id of the network
974     * @return {@code true} if the operation succeeds, {@code false} otherwise
975     */
976    public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
977        Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
978        boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
979        resultMsg.recycle();
980        return result;
981    }
982
983    /**
984     * Blacklist a BSSID. This will avoid the AP if there are
985     * alternate APs to connect
986     *
987     * @param bssid BSSID of the network
988     */
989    public void addToBlacklist(String bssid) {
990        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
991    }
992
993    /**
994     * Clear the blacklist list
995     *
996     */
997    public void clearBlacklist() {
998        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
999    }
1000
1001    public void enableRssiPolling(boolean enabled) {
1002       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
1003    }
1004
1005    public void enableBackgroundScanCommand(boolean enabled) {
1006       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
1007    }
1008
1009    public void enableAllNetworks() {
1010        sendMessage(CMD_ENABLE_ALL_NETWORKS);
1011    }
1012
1013    /**
1014     * Start filtering Multicast v4 packets
1015     */
1016    public void startFilteringMulticastV4Packets() {
1017        mFilteringMulticastV4Packets.set(true);
1018        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0));
1019    }
1020
1021    /**
1022     * Stop filtering Multicast v4 packets
1023     */
1024    public void stopFilteringMulticastV4Packets() {
1025        mFilteringMulticastV4Packets.set(false);
1026        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0));
1027    }
1028
1029    /**
1030     * Start filtering Multicast v4 packets
1031     */
1032    public void startFilteringMulticastV6Packets() {
1033        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0));
1034    }
1035
1036    /**
1037     * Stop filtering Multicast v4 packets
1038     */
1039    public void stopFilteringMulticastV6Packets() {
1040        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0));
1041    }
1042
1043    /**
1044     * Set high performance mode of operation.
1045     * Enabling would set active power mode and disable suspend optimizations;
1046     * disabling would set auto power mode and enable suspend optimizations
1047     * @param enable true if enable, false otherwise
1048     */
1049    public void setHighPerfModeEnabled(boolean enable) {
1050        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
1051    }
1052
1053    /**
1054     * Set the country code
1055     * @param countryCode following ISO 3166 format
1056     * @param persist {@code true} if the setting should be remembered.
1057     */
1058    public void setCountryCode(String countryCode, boolean persist) {
1059        if (persist) {
1060            Settings.Secure.putString(mContext.getContentResolver(),
1061                    Settings.Secure.WIFI_COUNTRY_CODE,
1062                    countryCode);
1063        }
1064        sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
1065    }
1066
1067    /**
1068     * Set the operational frequency band
1069     * @param band
1070     * @param persist {@code true} if the setting should be remembered.
1071     */
1072    public void setFrequencyBand(int band, boolean persist) {
1073        if (persist) {
1074            Settings.Secure.putInt(mContext.getContentResolver(),
1075                    Settings.Secure.WIFI_FREQUENCY_BAND,
1076                    band);
1077        }
1078        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
1079    }
1080
1081    /**
1082     * Returns the operational frequency band
1083     */
1084    public int getFrequencyBand() {
1085        return mFrequencyBand.get();
1086    }
1087
1088    /**
1089     * Returns the wifi configuration file
1090     */
1091    public String getConfigFile() {
1092        return mWifiConfigStore.getConfigFile();
1093    }
1094
1095    /**
1096     * Send a message indicating bluetooth adapter connection state changed
1097     */
1098    public void sendBluetoothAdapterStateChange(int state) {
1099        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
1100    }
1101
1102    /**
1103     * Save configuration on supplicant
1104     *
1105     * @return {@code true} if the operation succeeds, {@code false} otherwise
1106     *
1107     * TODO: deprecate this
1108     */
1109    public boolean syncSaveConfig(AsyncChannel channel) {
1110        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
1111        boolean result = (resultMsg.arg1 != FAILURE);
1112        resultMsg.recycle();
1113        return result;
1114    }
1115
1116    public void updateBatteryWorkSource(WorkSource newSource) {
1117        synchronized (mRunningWifiUids) {
1118            try {
1119                if (newSource != null) {
1120                    mRunningWifiUids.set(newSource);
1121                }
1122                if (mIsRunning) {
1123                    if (mReportedRunning) {
1124                        // If the work source has changed since last time, need
1125                        // to remove old work from battery stats.
1126                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
1127                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
1128                                    mRunningWifiUids);
1129                            mLastRunningWifiUids.set(mRunningWifiUids);
1130                        }
1131                    } else {
1132                        // Now being started, report it.
1133                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
1134                        mLastRunningWifiUids.set(mRunningWifiUids);
1135                        mReportedRunning = true;
1136                    }
1137                } else {
1138                    if (mReportedRunning) {
1139                        // Last reported we were running, time to stop.
1140                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
1141                        mLastRunningWifiUids.clear();
1142                        mReportedRunning = false;
1143                    }
1144                }
1145                mWakeLock.setWorkSource(newSource);
1146            } catch (RemoteException ignore) {
1147            }
1148        }
1149    }
1150
1151    @Override
1152    public String toString() {
1153        StringBuffer sb = new StringBuffer();
1154        String LS = System.getProperty("line.separator");
1155        sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
1156        sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
1157        sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
1158        sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
1159        sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
1160        sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
1161        sb.append("mLastBssid ").append(mLastBssid).append(LS);
1162        sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
1163        sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
1164        sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
1165        sb.append("mHighPerfMode").append(mHighPerfMode).append(LS);
1166        sb.append("mSuspendOptEnabled").append(mSuspendOptEnabled).append(LS);
1167        sb.append("Supplicant status").append(LS)
1168                .append(mWifiNative.status()).append(LS).append(LS);
1169
1170        sb.append(mWifiConfigStore.dump());
1171        return sb.toString();
1172    }
1173
1174    @Override
1175    protected boolean recordLogRec(Message msg) {
1176        //Ignore screen on/off & common messages when driver has started
1177        if (getCurrentState() == mConnectedState || getCurrentState() == mDisconnectedState) {
1178            switch (msg.what) {
1179                case CMD_LOAD_DRIVER:
1180                case CMD_START_SUPPLICANT:
1181                case CMD_START_DRIVER:
1182                case CMD_SET_SCAN_MODE:
1183                case CMD_SET_HIGH_PERF_MODE:
1184                case CMD_SET_SUSPEND_OPTIMIZATIONS:
1185                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
1186                case CMD_ENABLE_BACKGROUND_SCAN:
1187                case CMD_ENABLE_ALL_NETWORKS:
1188                return false;
1189            }
1190        }
1191
1192        switch (msg.what) {
1193            case CMD_START_SCAN:
1194            case CMD_ENABLE_RSSI_POLL:
1195            case CMD_RSSI_POLL:
1196            case CMD_DELAYED_STOP_DRIVER:
1197            case WifiMonitor.SCAN_RESULTS_EVENT:
1198            case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
1199                return false;
1200            default:
1201                return true;
1202        }
1203    }
1204
1205    /*********************************************************
1206     * Internal private functions
1207     ********************************************************/
1208
1209    private void checkAndSetConnectivityInstance() {
1210        if (mCm == null) {
1211            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1212        }
1213    }
1214
1215    private boolean startTethering(ArrayList<String> available) {
1216
1217        boolean wifiAvailable = false;
1218
1219        checkAndSetConnectivityInstance();
1220
1221        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1222
1223        for (String intf : available) {
1224            for (String regex : wifiRegexs) {
1225                if (intf.matches(regex)) {
1226
1227                    InterfaceConfiguration ifcg = null;
1228                    try {
1229                        ifcg = mNwService.getInterfaceConfig(intf);
1230                        if (ifcg != null) {
1231                            /* IP/netmask: 192.168.43.1/255.255.255.0 */
1232                            ifcg.setLinkAddress(new LinkAddress(
1233                                    NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
1234                            ifcg.setInterfaceUp();
1235
1236                            mNwService.setInterfaceConfig(intf, ifcg);
1237                        }
1238                    } catch (Exception e) {
1239                        loge("Error configuring interface " + intf + ", :" + e);
1240                        return false;
1241                    }
1242
1243                    if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1244                        loge("Error tethering on " + intf);
1245                        return false;
1246                    }
1247                    mTetherInterfaceName = intf;
1248                    return true;
1249                }
1250            }
1251        }
1252        // We found no interfaces to tether
1253        return false;
1254    }
1255
1256    private void stopTethering() {
1257
1258        checkAndSetConnectivityInstance();
1259
1260        /* Clear the interface config to allow dhcp correctly configure new
1261           ip settings */
1262        InterfaceConfiguration ifcg = null;
1263        try {
1264            ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
1265            if (ifcg != null) {
1266                ifcg.setLinkAddress(
1267                        new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
1268                mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
1269            }
1270        } catch (Exception e) {
1271            loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
1272        }
1273
1274        if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1275            loge("Untether initiate failed!");
1276        }
1277    }
1278
1279    private boolean isWifiTethered(ArrayList<String> active) {
1280
1281        checkAndSetConnectivityInstance();
1282
1283        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1284        for (String intf : active) {
1285            for (String regex : wifiRegexs) {
1286                if (intf.matches(regex)) {
1287                    return true;
1288                }
1289            }
1290        }
1291        // We found no interfaces that are tethered
1292        return false;
1293    }
1294
1295    /**
1296     * Set the country code from the system setting value, if any.
1297     */
1298    private void setCountryCode() {
1299        String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1300                Settings.Secure.WIFI_COUNTRY_CODE);
1301        if (countryCode != null && !countryCode.isEmpty()) {
1302            setCountryCode(countryCode, false);
1303        } else {
1304            //use driver default
1305        }
1306    }
1307
1308    /**
1309     * Set the frequency band from the system setting value, if any.
1310     */
1311    private void setFrequencyBand() {
1312        int band = Settings.Secure.getInt(mContext.getContentResolver(),
1313                Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1314        setFrequencyBand(band, false);
1315    }
1316
1317    private void setWifiState(int wifiState) {
1318        final int previousWifiState = mWifiState.get();
1319
1320        try {
1321            if (wifiState == WIFI_STATE_ENABLED) {
1322                mBatteryStats.noteWifiOn();
1323            } else if (wifiState == WIFI_STATE_DISABLED) {
1324                mBatteryStats.noteWifiOff();
1325            }
1326        } catch (RemoteException e) {
1327            loge("Failed to note battery stats in wifi");
1328        }
1329
1330        mWifiState.set(wifiState);
1331
1332        if (DBG) log("setWifiState: " + syncGetWifiStateByName());
1333
1334        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1335        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1336        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1337        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1338        mContext.sendStickyBroadcast(intent);
1339    }
1340
1341    private void setWifiApState(int wifiApState) {
1342        final int previousWifiApState = mWifiApState.get();
1343
1344        try {
1345            if (wifiApState == WIFI_AP_STATE_ENABLED) {
1346                mBatteryStats.noteWifiOn();
1347            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1348                mBatteryStats.noteWifiOff();
1349            }
1350        } catch (RemoteException e) {
1351            loge("Failed to note battery stats in wifi");
1352        }
1353
1354        // Update state
1355        mWifiApState.set(wifiApState);
1356
1357        if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
1358
1359        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1360        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1361        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1362        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1363        mContext.sendStickyBroadcast(intent);
1364    }
1365
1366    private static final String BSSID_STR = "bssid=";
1367    private static final String FREQ_STR = "freq=";
1368    private static final String LEVEL_STR = "level=";
1369    private static final String TSF_STR = "tsf=";
1370    private static final String FLAGS_STR = "flags=";
1371    private static final String SSID_STR = "ssid=";
1372    private static final String DELIMITER_STR = "====";
1373    /**
1374     * Format:
1375     * bssid=68:7f:76:d7:1a:6e
1376     * freq=2412
1377     * level=-44
1378     * tsf=1344626243700342
1379     * flags=[WPA2-PSK-CCMP][WPS][ESS]
1380     * ssid=zfdy
1381     * ====
1382     * bssid=68:5f:74:d7:1a:6f
1383     * freq=5180
1384     * level=-73
1385     * tsf=1344626243700373
1386     * flags=[WPA2-PSK-CCMP][WPS][ESS]
1387     * ssid=zuby
1388     * ====
1389     */
1390    private void setScanResults(String scanResults) {
1391        String bssid = "";
1392        int level = 0;
1393        int freq = 0;
1394        long tsf = 0;
1395        String flags = "";
1396        String ssid = "";
1397
1398        if (scanResults == null) {
1399            return;
1400        }
1401
1402        synchronized(mScanResultCache) {
1403            mScanResults = new ArrayList<ScanResult>();
1404            String[] lines = scanResults.split("\n");
1405
1406            for (String line : lines) {
1407                if (line.startsWith(BSSID_STR)) {
1408                    bssid = line.substring(BSSID_STR.length());
1409                } else if (line.startsWith(FREQ_STR)) {
1410                    try {
1411                        freq = Integer.parseInt(line.substring(FREQ_STR.length()));
1412                    } catch (NumberFormatException e) {
1413                        freq = 0;
1414                    }
1415                } else if (line.startsWith(LEVEL_STR)) {
1416                    try {
1417                        level = Integer.parseInt(line.substring(LEVEL_STR.length()));
1418                        /* some implementations avoid negative values by adding 256
1419                         * so we need to adjust for that here.
1420                         */
1421                        if (level > 0) level -= 256;
1422                    } catch(NumberFormatException e) {
1423                        level = 0;
1424                    }
1425                } else if (line.startsWith(TSF_STR)) {
1426                    try {
1427                        tsf = Long.parseLong(line.substring(TSF_STR.length()));
1428                    } catch (NumberFormatException e) {
1429                        tsf = 0;
1430                    }
1431                } else if (line.startsWith(FLAGS_STR)) {
1432                    flags = line.substring(FLAGS_STR.length());
1433                } else if (line.startsWith(SSID_STR)) {
1434                    ssid = line.substring(SSID_STR.length());
1435                    if (ssid == null) ssid = "";
1436                } else if (line.startsWith(DELIMITER_STR)) {
1437                    if (bssid != null) {
1438                        String key = bssid + ssid;
1439                        ScanResult scanResult = mScanResultCache.get(key);
1440                        if (scanResult != null) {
1441                            scanResult.level = level;
1442                            scanResult.SSID = ssid;
1443                            scanResult.capabilities = flags;
1444                            scanResult.frequency = freq;
1445                            scanResult.timestamp = tsf;
1446                        } else {
1447                            scanResult =
1448                                new ScanResult(
1449                                        ssid, bssid, flags, level, freq, tsf);
1450                            mScanResultCache.put(key, scanResult);
1451                        }
1452                        mScanResults.add(scanResult);
1453                    }
1454                    bssid = null;
1455                    level = 0;
1456                    freq = 0;
1457                    tsf = 0;
1458                    flags = "";
1459                    ssid = "";
1460                }
1461            }
1462        }
1463    }
1464
1465    /*
1466     * Fetch RSSI and linkspeed on current connection
1467     */
1468    private void fetchRssiAndLinkSpeedNative() {
1469        int newRssi = -1;
1470        int newLinkSpeed = -1;
1471
1472        String signalPoll = mWifiNative.signalPoll();
1473
1474        if (signalPoll != null) {
1475            String[] lines = signalPoll.split("\n");
1476            for (String line : lines) {
1477                String[] prop = line.split("=");
1478                if (prop.length < 2) continue;
1479                try {
1480                    if (prop[0].equals("RSSI")) {
1481                        newRssi = Integer.parseInt(prop[1]);
1482                    } else if (prop[0].equals("LINKSPEED")) {
1483                        newLinkSpeed = Integer.parseInt(prop[1]);
1484                    }
1485                } catch (NumberFormatException e) {
1486                    //Ignore, defaults on rssi and linkspeed are assigned
1487                }
1488            }
1489        }
1490
1491        if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1492            /* some implementations avoid negative values by adding 256
1493             * so we need to adjust for that here.
1494             */
1495            if (newRssi > 0) newRssi -= 256;
1496            mWifiInfo.setRssi(newRssi);
1497            /*
1498             * Rather then sending the raw RSSI out every time it
1499             * changes, we precalculate the signal level that would
1500             * be displayed in the status bar, and only send the
1501             * broadcast if that much more coarse-grained number
1502             * changes. This cuts down greatly on the number of
1503             * broadcasts, at the cost of not informing others
1504             * interested in RSSI of all the changes in signal
1505             * level.
1506             */
1507            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
1508            if (newSignalLevel != mLastSignalLevel) {
1509                sendRssiChangeBroadcast(newRssi);
1510            }
1511            mLastSignalLevel = newSignalLevel;
1512        } else {
1513            mWifiInfo.setRssi(MIN_RSSI);
1514        }
1515
1516        if (newLinkSpeed != -1) {
1517            mWifiInfo.setLinkSpeed(newLinkSpeed);
1518        }
1519    }
1520
1521    /*
1522     * Fetch TX packet counters on current connection
1523     */
1524    private void fetchPktcntNative(RssiPktcntStat stat) {
1525        String pktcntPoll = mWifiNative.pktcntPoll();
1526
1527        if (pktcntPoll != null) {
1528            String[] lines = pktcntPoll.split("\n");
1529            for (String line : lines) {
1530                String[] prop = line.split("=");
1531                if (prop.length < 2) continue;
1532                try {
1533                    if (prop[0].equals("TXGOOD")) {
1534                        stat.txgood = Integer.parseInt(prop[1]);
1535                    } else if (prop[0].equals("TXBAD")) {
1536                        stat.txbad = Integer.parseInt(prop[1]);
1537                    }
1538                } catch (NumberFormatException e) {
1539                    //Ignore
1540                }
1541            }
1542        }
1543    }
1544
1545    private void configureLinkProperties() {
1546        if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1547            mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId);
1548        } else {
1549            synchronized (mDhcpInfoInternal) {
1550                mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1551            }
1552            mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1553        }
1554        mLinkProperties.setInterfaceName(mInterfaceName);
1555        if (DBG) {
1556            log("netId=" + mLastNetworkId  + " Link configured: " +
1557                    mLinkProperties.toString());
1558        }
1559    }
1560
1561    private int getMaxDhcpRetries() {
1562        return Settings.Secure.getInt(mContext.getContentResolver(),
1563                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1564                                      DEFAULT_MAX_DHCP_RETRIES);
1565    }
1566
1567    private void sendScanResultsAvailableBroadcast() {
1568        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1569        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1570        mContext.sendBroadcast(intent);
1571    }
1572
1573    private void sendRssiChangeBroadcast(final int newRssi) {
1574        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1575        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1576        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1577        mContext.sendBroadcast(intent);
1578    }
1579
1580    private void sendNetworkStateChangeBroadcast(String bssid) {
1581        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1582        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1583        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
1584        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1585        if (bssid != null)
1586            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1587        if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
1588                mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
1589            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
1590        }
1591        mContext.sendStickyBroadcast(intent);
1592    }
1593
1594    private void sendLinkConfigurationChangedBroadcast() {
1595        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1596        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1597        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1598        mContext.sendBroadcast(intent);
1599    }
1600
1601    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1602        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1603        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1604        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1605        mContext.sendBroadcast(intent);
1606    }
1607
1608    /**
1609     * Record the detailed state of a network.
1610     * @param state the new {@code DetailedState}
1611     */
1612    private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1613        if (DBG) {
1614            log("setDetailed state, old ="
1615                    + mNetworkInfo.getDetailedState() + " and new state=" + state);
1616        }
1617
1618        if (state != mNetworkInfo.getDetailedState()) {
1619            mNetworkInfo.setDetailedState(state, null, null);
1620        }
1621    }
1622
1623    private DetailedState getNetworkDetailedState() {
1624        return mNetworkInfo.getDetailedState();
1625    }
1626
1627
1628    private SupplicantState handleSupplicantStateChange(Message message) {
1629        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
1630        SupplicantState state = stateChangeResult.state;
1631        // Supplicant state change
1632        // [31-13] Reserved for future use
1633        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
1634        // 50023 supplicant_state_changed (custom|1|5)
1635        EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
1636        mWifiInfo.setSupplicantState(state);
1637        // Network id is only valid when we start connecting
1638        if (SupplicantState.isConnecting(state)) {
1639            mWifiInfo.setNetworkId(stateChangeResult.networkId);
1640        } else {
1641            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1642        }
1643
1644        mWifiInfo.setBSSID(stateChangeResult.BSSID);
1645        mWifiInfo.setSSID(stateChangeResult.SSID);
1646
1647        mSupplicantStateTracker.sendMessage(Message.obtain(message));
1648
1649        return state;
1650    }
1651
1652    /**
1653     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1654     * using the interface, stopping DHCP & disabling interface
1655     */
1656    private void handleNetworkDisconnect() {
1657        if (DBG) log("Stopping DHCP and clearing IP");
1658
1659        /*
1660         * stop DHCP
1661         */
1662        if (mDhcpStateMachine != null) {
1663            /* In case we were in middle of DHCP operation
1664               restore back powermode */
1665            handlePostDhcpSetup();
1666
1667            mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1668            mDhcpStateMachine.doQuit();
1669            mDhcpStateMachine = null;
1670        }
1671
1672        try {
1673            mNwService.clearInterfaceAddresses(mInterfaceName);
1674            mNwService.disableIpv6(mInterfaceName);
1675        } catch (Exception e) {
1676            loge("Failed to clear addresses or disable ipv6" + e);
1677        }
1678
1679        /* Reset data structures */
1680        mWifiInfo.setInetAddress(null);
1681        mWifiInfo.setBSSID(null);
1682        mWifiInfo.setSSID(null);
1683        mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1684        mWifiInfo.setRssi(MIN_RSSI);
1685        mWifiInfo.setLinkSpeed(-1);
1686        mWifiInfo.setMeteredHint(false);
1687
1688        setNetworkDetailedState(DetailedState.DISCONNECTED);
1689        mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
1690
1691        /* send event to CM & network change broadcast */
1692        sendNetworkStateChangeBroadcast(mLastBssid);
1693
1694        /* Clear network properties */
1695        mLinkProperties.clear();
1696        /* Clear IP settings if the network used DHCP */
1697        if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1698            mWifiConfigStore.clearIpConfiguration(mLastNetworkId);
1699        }
1700
1701        mLastBssid= null;
1702        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1703    }
1704
1705    void handlePreDhcpSetup() {
1706        if (!mBluetoothConnectionActive) {
1707            /*
1708             * There are problems setting the Wi-Fi driver's power
1709             * mode to active when bluetooth coexistence mode is
1710             * enabled or sense.
1711             * <p>
1712             * We set Wi-Fi to active mode when
1713             * obtaining an IP address because we've found
1714             * compatibility issues with some routers with low power
1715             * mode.
1716             * <p>
1717             * In order for this active power mode to properly be set,
1718             * we disable coexistence mode until we're done with
1719             * obtaining an IP address.  One exception is if we
1720             * are currently connected to a headset, since disabling
1721             * coexistence would interrupt that connection.
1722             */
1723            // Disable the coexistence mode
1724            mWifiNative.setBluetoothCoexistenceMode(
1725                    mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1726        }
1727
1728        /* Disable power save during DHCP */
1729        if (mPowerSaveEnabled) {
1730            mPowerSaveEnabled = false;
1731            mWifiNative.setPowerSave(mPowerSaveEnabled);
1732        }
1733    }
1734
1735
1736    void handlePostDhcpSetup() {
1737        /* Restore power save */
1738        mPowerSaveEnabled = true;
1739        mWifiNative.setPowerSave(mPowerSaveEnabled);
1740
1741        // Set the coexistence mode back to its default value
1742        mWifiNative.setBluetoothCoexistenceMode(
1743                mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1744    }
1745
1746    private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
1747        synchronized (mDhcpInfoInternal) {
1748            mDhcpInfoInternal = dhcpInfoInternal;
1749        }
1750        mLastSignalLevel = -1; // force update of signal strength
1751        mReconnectCount = 0; //Reset IP failure tracking
1752        mWifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
1753        InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
1754        mWifiInfo.setInetAddress(addr);
1755        mWifiInfo.setMeteredHint(dhcpInfoInternal.hasMeteredHint());
1756        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1757            //DHCP renewal in connected state
1758            LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
1759            linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1760            linkProperties.setInterfaceName(mInterfaceName);
1761            if (!linkProperties.equals(mLinkProperties)) {
1762                if (DBG) {
1763                    log("Link configuration changed for netId: " + mLastNetworkId
1764                            + " old: " + mLinkProperties + "new: " + linkProperties);
1765                }
1766                mLinkProperties = linkProperties;
1767                sendLinkConfigurationChangedBroadcast();
1768            }
1769        } else {
1770            configureLinkProperties();
1771        }
1772    }
1773
1774    private void handleFailedIpConfiguration() {
1775        loge("IP configuration failed");
1776
1777        mWifiInfo.setInetAddress(null);
1778        mWifiInfo.setMeteredHint(false);
1779        /**
1780         * If we've exceeded the maximum number of retries for DHCP
1781         * to a given network, disable the network
1782         */
1783        int maxRetries = getMaxDhcpRetries();
1784        // maxRetries == 0 means keep trying forever
1785        if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
1786            loge("Failed " +
1787                    mReconnectCount + " times, Disabling " + mLastNetworkId);
1788            mWifiConfigStore.disableNetwork(mLastNetworkId,
1789                    WifiConfiguration.DISABLED_DHCP_FAILURE);
1790            mReconnectCount = 0;
1791        }
1792
1793        /* DHCP times out after about 30 seconds, we do a
1794         * disconnect and an immediate reconnect to try again
1795         */
1796        mWifiNative.disconnect();
1797        mWifiNative.reconnect();
1798    }
1799
1800    /* Current design is to not set the config on a running hostapd but instead
1801     * stop and start tethering when user changes config on a running access point
1802     *
1803     * TODO: Add control channel setup through hostapd that allows changing config
1804     * on a running daemon
1805     */
1806    private void startSoftApWithConfig(final WifiConfiguration config) {
1807        // start hostapd on a seperate thread
1808        new Thread(new Runnable() {
1809            public void run() {
1810                try {
1811                    mNwService.startAccessPoint(config, mInterfaceName);
1812                } catch (Exception e) {
1813                    loge("Exception in softap start " + e);
1814                    try {
1815                        mNwService.stopAccessPoint(mInterfaceName);
1816                        mNwService.startAccessPoint(config, mInterfaceName);
1817                    } catch (Exception e1) {
1818                        loge("Exception in softap re-start " + e1);
1819                        sendMessage(CMD_START_AP_FAILURE);
1820                        return;
1821                    }
1822                }
1823                if (DBG) log("Soft AP start successful");
1824                sendMessage(CMD_START_AP_SUCCESS);
1825            }
1826        }).start();
1827    }
1828
1829    /********************************************************
1830     * HSM states
1831     *******************************************************/
1832
1833    class DefaultState extends State {
1834        @Override
1835        public boolean processMessage(Message message) {
1836            if (DBG) log(getName() + message.toString() + "\n");
1837            switch (message.what) {
1838                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1839                    if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1840                        mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1841                    } else {
1842                        loge("WifiP2pService connection failure, error=" + message.arg1);
1843                    }
1844                    break;
1845                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1846                    loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
1847                    //TODO: Re-establish connection to state machine after a delay
1848                    //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
1849                    break;
1850                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1851                    mBluetoothConnectionActive = (message.arg1 !=
1852                            BluetoothAdapter.STATE_DISCONNECTED);
1853                    break;
1854                    /* Synchronous call returns */
1855                case CMD_PING_SUPPLICANT:
1856                case CMD_ENABLE_NETWORK:
1857                case CMD_ADD_OR_UPDATE_NETWORK:
1858                case CMD_REMOVE_NETWORK:
1859                case CMD_SAVE_CONFIG:
1860                    replyToMessage(message, message.what, FAILURE);
1861                    break;
1862                case CMD_GET_CONFIGURED_NETWORKS:
1863                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
1864                    break;
1865                case CMD_ENABLE_RSSI_POLL:
1866                    mEnableRssiPolling = (message.arg1 == 1);
1867                    break;
1868                case CMD_ENABLE_BACKGROUND_SCAN:
1869                    mEnableBackgroundScan = (message.arg1 == 1);
1870                    break;
1871                case CMD_SET_HIGH_PERF_MODE:
1872                    mHighPerfMode = (message.arg1 == 1);
1873                    break;
1874                    /* Discard */
1875                case CMD_LOAD_DRIVER:
1876                case CMD_UNLOAD_DRIVER:
1877                case CMD_START_SUPPLICANT:
1878                case CMD_STOP_SUPPLICANT:
1879                case CMD_STOP_SUPPLICANT_FAILED:
1880                case CMD_START_DRIVER:
1881                case CMD_STOP_DRIVER:
1882                case CMD_DELAYED_STOP_DRIVER:
1883                case CMD_DRIVER_START_TIMED_OUT:
1884                case CMD_START_AP:
1885                case CMD_START_AP_SUCCESS:
1886                case CMD_START_AP_FAILURE:
1887                case CMD_STOP_AP:
1888                case CMD_TETHER_STATE_CHANGE:
1889                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
1890                case CMD_START_SCAN:
1891                case CMD_DISCONNECT:
1892                case CMD_RECONNECT:
1893                case CMD_REASSOCIATE:
1894                case WifiMonitor.SUP_CONNECTION_EVENT:
1895                case WifiMonitor.SUP_DISCONNECTION_EVENT:
1896                case WifiMonitor.NETWORK_CONNECTION_EVENT:
1897                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
1898                case WifiMonitor.SCAN_RESULTS_EVENT:
1899                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
1900                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
1901                case WifiMonitor.WPS_OVERLAP_EVENT:
1902                case CMD_BLACKLIST_NETWORK:
1903                case CMD_CLEAR_BLACKLIST:
1904                case CMD_SET_SCAN_MODE:
1905                case CMD_SET_SCAN_TYPE:
1906                case CMD_SET_COUNTRY_CODE:
1907                case CMD_SET_FREQUENCY_BAND:
1908                case CMD_RSSI_POLL:
1909                case CMD_ENABLE_ALL_NETWORKS:
1910                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1911                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1912                /* Handled by WifiApConfigStore */
1913                case CMD_SET_AP_CONFIG:
1914                case CMD_SET_AP_CONFIG_COMPLETED:
1915                case CMD_REQUEST_AP_CONFIG:
1916                case CMD_RESPONSE_AP_CONFIG:
1917                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
1918                case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
1919                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
1920                case CMD_NO_NETWORKS_PERIODIC_SCAN:
1921                    break;
1922                case CMD_SET_SUSPEND_OPTIMIZATIONS:
1923                    mSuspendWakeLock.release();
1924                    break;
1925                case WifiMonitor.DRIVER_HUNG_EVENT:
1926                    setWifiEnabled(false);
1927                    setWifiEnabled(true);
1928                    break;
1929                case WifiManager.CONNECT_NETWORK:
1930                    replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
1931                            WifiManager.BUSY);
1932                    break;
1933                case WifiManager.FORGET_NETWORK:
1934                    replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
1935                            WifiManager.BUSY);
1936                    break;
1937                case WifiManager.SAVE_NETWORK:
1938                    replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
1939                            WifiManager.BUSY);
1940                    break;
1941                case WifiManager.START_WPS:
1942                    replyToMessage(message, WifiManager.WPS_FAILED,
1943                            WifiManager.BUSY);
1944                    break;
1945                case WifiManager.CANCEL_WPS:
1946                    replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
1947                            WifiManager.BUSY);
1948                    break;
1949                case WifiManager.DISABLE_NETWORK:
1950                    replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
1951                            WifiManager.BUSY);
1952                    break;
1953                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
1954                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_FAILED);
1955                    break;
1956                default:
1957                    loge("Error! unhandled message" + message);
1958                    break;
1959            }
1960            return HANDLED;
1961        }
1962    }
1963
1964    class InitialState extends State {
1965        @Override
1966        //TODO: could move logging into a common class
1967        public void enter() {
1968            if (DBG) log(getName() + "\n");
1969            // [31-8] Reserved for future use
1970            // [7 - 0] HSM state change
1971            // 50021 wifi_state_changed (custom|1|5)
1972            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1973
1974            if (mWifiNative.isDriverLoaded()) {
1975                transitionTo(mDriverLoadedState);
1976            }
1977            else {
1978                transitionTo(mDriverUnloadedState);
1979            }
1980
1981            //Connect to WifiP2pService
1982            mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
1983            mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
1984
1985            /* IPv6 is disabled at boot time and is controlled by framework
1986             * to be enabled only as long as we are connected to an access point
1987             *
1988             * This fixes issues, a few being:
1989             * - IPv6 addresses and routes stick around after disconnection
1990             * - When connected, the kernel is unaware and can fail to start IPv6 negotiation
1991             * - The kernel sometimes starts autoconfiguration when 802.1x is not complete
1992             */
1993            try {
1994                mNwService.disableIpv6(mInterfaceName);
1995            } catch (RemoteException re) {
1996                loge("Failed to disable IPv6: " + re);
1997            } catch (IllegalStateException e) {
1998                loge("Failed to disable IPv6: " + e);
1999            }
2000        }
2001    }
2002
2003    class DriverLoadingState extends State {
2004        @Override
2005        public void enter() {
2006            if (DBG) log(getName() + "\n");
2007            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2008
2009            final Message message = new Message();
2010            message.copyFrom(getCurrentMessage());
2011            /* TODO: add a timeout to fail when driver load is hung.
2012             * Similarly for driver unload.
2013             */
2014            new Thread(new Runnable() {
2015                public void run() {
2016                    mWakeLock.acquire();
2017                    //enabling state
2018                    switch(message.arg1) {
2019                        case WIFI_STATE_ENABLING:
2020                            setWifiState(WIFI_STATE_ENABLING);
2021                            break;
2022                        case WIFI_AP_STATE_ENABLING:
2023                            setWifiApState(WIFI_AP_STATE_ENABLING);
2024                            break;
2025                    }
2026
2027                    if(mWifiNative.loadDriver()) {
2028                        if (DBG) log("Driver load successful");
2029                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
2030                    } else {
2031                        loge("Failed to load driver!");
2032                        switch(message.arg1) {
2033                            case WIFI_STATE_ENABLING:
2034                                setWifiState(WIFI_STATE_UNKNOWN);
2035                                break;
2036                            case WIFI_AP_STATE_ENABLING:
2037                                setWifiApState(WIFI_AP_STATE_FAILED);
2038                                break;
2039                        }
2040                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
2041                    }
2042                    mWakeLock.release();
2043                }
2044            }).start();
2045        }
2046
2047        @Override
2048        public boolean processMessage(Message message) {
2049            if (DBG) log(getName() + message.toString() + "\n");
2050            switch (message.what) {
2051                case CMD_LOAD_DRIVER_SUCCESS:
2052                    transitionTo(mDriverLoadedState);
2053                    break;
2054                case CMD_LOAD_DRIVER_FAILURE:
2055                    transitionTo(mDriverFailedState);
2056                    break;
2057                case CMD_LOAD_DRIVER:
2058                case CMD_UNLOAD_DRIVER:
2059                case CMD_START_SUPPLICANT:
2060                case CMD_STOP_SUPPLICANT:
2061                case CMD_START_AP:
2062                case CMD_STOP_AP:
2063                case CMD_START_DRIVER:
2064                case CMD_STOP_DRIVER:
2065                case CMD_SET_SCAN_MODE:
2066                case CMD_SET_SCAN_TYPE:
2067                case CMD_SET_COUNTRY_CODE:
2068                case CMD_SET_FREQUENCY_BAND:
2069                case CMD_START_PACKET_FILTERING:
2070                case CMD_STOP_PACKET_FILTERING:
2071                    deferMessage(message);
2072                    break;
2073                default:
2074                    return NOT_HANDLED;
2075            }
2076            return HANDLED;
2077        }
2078    }
2079
2080    class DriverLoadedState extends State {
2081        @Override
2082        public void enter() {
2083            if (DBG) log(getName() + "\n");
2084            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2085        }
2086        @Override
2087        public boolean processMessage(Message message) {
2088            if (DBG) log(getName() + message.toString() + "\n");
2089            switch(message.what) {
2090                case CMD_UNLOAD_DRIVER:
2091                    transitionTo(mDriverUnloadingState);
2092                    break;
2093                case CMD_START_SUPPLICANT:
2094                    try {
2095                        mNwService.wifiFirmwareReload(mInterfaceName, "STA");
2096                    } catch (Exception e) {
2097                        loge("Failed to reload STA firmware " + e);
2098                        // continue
2099                    }
2100                   try {
2101                       //A runtime crash can leave the interface up and
2102                       //this affects connectivity when supplicant starts up.
2103                       //Ensure interface is down before a supplicant start.
2104                        mNwService.setInterfaceDown(mInterfaceName);
2105                        //Set privacy extensions
2106                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
2107                    } catch (RemoteException re) {
2108                        loge("Unable to change interface settings: " + re);
2109                    } catch (IllegalStateException ie) {
2110                        loge("Unable to change interface settings: " + ie);
2111                    }
2112
2113                    if(mWifiNative.startSupplicant(mP2pSupported)) {
2114                        if (DBG) log("Supplicant start successful");
2115                        mWifiMonitor.startMonitoring();
2116                        transitionTo(mSupplicantStartingState);
2117                    } else {
2118                        loge("Failed to start supplicant!");
2119                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2120                    }
2121                    break;
2122                case CMD_START_AP:
2123                    transitionTo(mSoftApStartingState);
2124                    break;
2125                default:
2126                    return NOT_HANDLED;
2127            }
2128            return HANDLED;
2129        }
2130    }
2131
2132    class DriverUnloadingState extends State {
2133        @Override
2134        public void enter() {
2135            if (DBG) log(getName() + "\n");
2136            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2137
2138            final Message message = new Message();
2139            message.copyFrom(getCurrentMessage());
2140            new Thread(new Runnable() {
2141                public void run() {
2142                    if (DBG) log(getName() + message.toString() + "\n");
2143                    mWakeLock.acquire();
2144                    if(mWifiNative.unloadDriver()) {
2145                        if (DBG) log("Driver unload successful");
2146                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
2147
2148                        switch(message.arg1) {
2149                            case WIFI_STATE_DISABLED:
2150                            case WIFI_STATE_UNKNOWN:
2151                                setWifiState(message.arg1);
2152                                break;
2153                            case WIFI_AP_STATE_DISABLED:
2154                            case WIFI_AP_STATE_FAILED:
2155                                setWifiApState(message.arg1);
2156                                break;
2157                        }
2158                    } else {
2159                        loge("Failed to unload driver!");
2160                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
2161
2162                        switch(message.arg1) {
2163                            case WIFI_STATE_DISABLED:
2164                            case WIFI_STATE_UNKNOWN:
2165                                setWifiState(WIFI_STATE_UNKNOWN);
2166                                break;
2167                            case WIFI_AP_STATE_DISABLED:
2168                            case WIFI_AP_STATE_FAILED:
2169                                setWifiApState(WIFI_AP_STATE_FAILED);
2170                                break;
2171                        }
2172                    }
2173                    mWakeLock.release();
2174                }
2175            }).start();
2176        }
2177
2178        @Override
2179        public boolean processMessage(Message message) {
2180            if (DBG) log(getName() + message.toString() + "\n");
2181            switch (message.what) {
2182                case CMD_UNLOAD_DRIVER_SUCCESS:
2183                    transitionTo(mDriverUnloadedState);
2184                    break;
2185                case CMD_UNLOAD_DRIVER_FAILURE:
2186                    transitionTo(mDriverFailedState);
2187                    break;
2188                case CMD_LOAD_DRIVER:
2189                case CMD_UNLOAD_DRIVER:
2190                case CMD_START_SUPPLICANT:
2191                case CMD_STOP_SUPPLICANT:
2192                case CMD_START_AP:
2193                case CMD_STOP_AP:
2194                case CMD_START_DRIVER:
2195                case CMD_STOP_DRIVER:
2196                case CMD_SET_SCAN_MODE:
2197                case CMD_SET_SCAN_TYPE:
2198                case CMD_SET_COUNTRY_CODE:
2199                case CMD_SET_FREQUENCY_BAND:
2200                case CMD_START_PACKET_FILTERING:
2201                case CMD_STOP_PACKET_FILTERING:
2202                    deferMessage(message);
2203                    break;
2204                default:
2205                    return NOT_HANDLED;
2206            }
2207            return HANDLED;
2208        }
2209    }
2210
2211    class DriverUnloadedState extends State {
2212        @Override
2213        public void enter() {
2214            if (DBG) log(getName() + "\n");
2215            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2216        }
2217        @Override
2218        public boolean processMessage(Message message) {
2219            if (DBG) log(getName() + message.toString() + "\n");
2220            switch (message.what) {
2221                case CMD_LOAD_DRIVER:
2222                    transitionTo(mDriverLoadingState);
2223                    break;
2224                default:
2225                    return NOT_HANDLED;
2226            }
2227            return HANDLED;
2228        }
2229    }
2230
2231    class DriverFailedState extends State {
2232        @Override
2233        public void enter() {
2234            loge(getName() + "\n");
2235            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2236        }
2237        @Override
2238        public boolean processMessage(Message message) {
2239            if (DBG) log(getName() + message.toString() + "\n");
2240            return NOT_HANDLED;
2241        }
2242    }
2243
2244
2245    class SupplicantStartingState extends State {
2246        @Override
2247        public void enter() {
2248            if (DBG) log(getName() + "\n");
2249            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2250        }
2251
2252        private void initializeWpsDetails() {
2253            String detail;
2254            detail = SystemProperties.get("ro.product.name", "");
2255            if (!mWifiNative.setDeviceName(detail)) {
2256                loge("Failed to set device name " +  detail);
2257            }
2258            detail = SystemProperties.get("ro.product.manufacturer", "");
2259            if (!mWifiNative.setManufacturer(detail)) {
2260                loge("Failed to set manufacturer " + detail);
2261            }
2262            detail = SystemProperties.get("ro.product.model", "");
2263            if (!mWifiNative.setModelName(detail)) {
2264                loge("Failed to set model name " + detail);
2265            }
2266            detail = SystemProperties.get("ro.product.model", "");
2267            if (!mWifiNative.setModelNumber(detail)) {
2268                loge("Failed to set model number " + detail);
2269            }
2270            detail = SystemProperties.get("ro.serialno", "");
2271            if (!mWifiNative.setSerialNumber(detail)) {
2272                loge("Failed to set serial number " + detail);
2273            }
2274            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) {
2275                loge("Failed to set WPS config methods");
2276            }
2277            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
2278                loge("Failed to set primary device type " + mPrimaryDeviceType);
2279            }
2280        }
2281
2282        @Override
2283        public boolean processMessage(Message message) {
2284            if (DBG) log(getName() + message.toString() + "\n");
2285            switch(message.what) {
2286                case WifiMonitor.SUP_CONNECTION_EVENT:
2287                    if (DBG) log("Supplicant connection established");
2288                    setWifiState(WIFI_STATE_ENABLED);
2289                    mSupplicantRestartCount = 0;
2290                    /* Reset the supplicant state to indicate the supplicant
2291                     * state is not known at this time */
2292                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2293                    /* Initialize data structures */
2294                    mLastBssid = null;
2295                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2296                    mLastSignalLevel = -1;
2297
2298                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
2299                    mWifiConfigStore.initialize();
2300                    initializeWpsDetails();
2301
2302                    sendSupplicantConnectionChangedBroadcast(true);
2303                    transitionTo(mDriverStartedState);
2304                    break;
2305                case WifiMonitor.SUP_DISCONNECTION_EVENT:
2306                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2307                        loge("Failed to setup control channel, restart supplicant");
2308                        mWifiNative.killSupplicant();
2309                        transitionTo(mDriverLoadedState);
2310                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2311                    } else {
2312                        loge("Failed " + mSupplicantRestartCount +
2313                                " times to start supplicant, unload driver");
2314                        mSupplicantRestartCount = 0;
2315                        transitionTo(mDriverLoadedState);
2316                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2317                    }
2318                    break;
2319                case CMD_LOAD_DRIVER:
2320                case CMD_UNLOAD_DRIVER:
2321                case CMD_START_SUPPLICANT:
2322                case CMD_STOP_SUPPLICANT:
2323                case CMD_START_AP:
2324                case CMD_STOP_AP:
2325                case CMD_START_DRIVER:
2326                case CMD_STOP_DRIVER:
2327                case CMD_SET_SCAN_MODE:
2328                case CMD_SET_SCAN_TYPE:
2329                case CMD_SET_COUNTRY_CODE:
2330                case CMD_SET_FREQUENCY_BAND:
2331                case CMD_START_PACKET_FILTERING:
2332                case CMD_STOP_PACKET_FILTERING:
2333                    deferMessage(message);
2334                    break;
2335                default:
2336                    return NOT_HANDLED;
2337            }
2338            return HANDLED;
2339        }
2340    }
2341
2342    class SupplicantStartedState extends State {
2343        @Override
2344        public void enter() {
2345            if (DBG) log(getName() + "\n");
2346            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2347            /* Initialize for connect mode operation at start */
2348            mIsScanMode = false;
2349            /* Wifi is available as long as we have a connection to supplicant */
2350            mNetworkInfo.setIsAvailable(true);
2351
2352            int defaultInterval = mContext.getResources().getInteger(
2353                    com.android.internal.R.integer.config_wifi_supplicant_scan_interval);
2354
2355            mSupplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2356                    Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2357                    defaultInterval);
2358
2359            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
2360        }
2361        @Override
2362        public boolean processMessage(Message message) {
2363            if (DBG) log(getName() + message.toString() + "\n");
2364            WifiConfiguration config;
2365            switch(message.what) {
2366                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
2367                    transitionTo(mSupplicantStoppingState);
2368                    break;
2369                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
2370                    loge("Connection lost, restart supplicant");
2371                    mWifiNative.killSupplicant();
2372                    mWifiNative.closeSupplicantConnection();
2373                    mNetworkInfo.setIsAvailable(false);
2374                    handleNetworkDisconnect();
2375                    sendSupplicantConnectionChangedBroadcast(false);
2376                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2377                    transitionTo(mDriverLoadedState);
2378                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2379                    break;
2380                case WifiMonitor.SCAN_RESULTS_EVENT:
2381                    setScanResults(mWifiNative.scanResults());
2382                    sendScanResultsAvailableBroadcast();
2383                    mScanResultIsPending = false;
2384                    break;
2385                case CMD_PING_SUPPLICANT:
2386                    boolean ok = mWifiNative.ping();
2387                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2388                    break;
2389                case CMD_ADD_OR_UPDATE_NETWORK:
2390                    config = (WifiConfiguration) message.obj;
2391                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2392                            mWifiConfigStore.addOrUpdateNetwork(config));
2393                    break;
2394                case CMD_REMOVE_NETWORK:
2395                    ok = mWifiConfigStore.removeNetwork(message.arg1);
2396                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2397                    break;
2398                case CMD_ENABLE_NETWORK:
2399                    ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2400                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2401                    break;
2402                case CMD_ENABLE_ALL_NETWORKS:
2403                    long time =  android.os.SystemClock.elapsedRealtime();
2404                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
2405                        mWifiConfigStore.enableAllNetworks();
2406                        mLastEnableAllNetworksTime = time;
2407                    }
2408                    break;
2409                case WifiManager.DISABLE_NETWORK:
2410                    if (mWifiConfigStore.disableNetwork(message.arg1,
2411                            WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
2412                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
2413                    } else {
2414                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
2415                                WifiManager.ERROR);
2416                    }
2417                    break;
2418                case CMD_BLACKLIST_NETWORK:
2419                    mWifiNative.addToBlacklist((String)message.obj);
2420                    break;
2421                case CMD_CLEAR_BLACKLIST:
2422                    mWifiNative.clearBlacklist();
2423                    break;
2424                case CMD_SAVE_CONFIG:
2425                    ok = mWifiConfigStore.saveConfig();
2426                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2427
2428                    // Inform the backup manager about a data change
2429                    IBackupManager ibm = IBackupManager.Stub.asInterface(
2430                            ServiceManager.getService(Context.BACKUP_SERVICE));
2431                    if (ibm != null) {
2432                        try {
2433                            ibm.dataChanged("com.android.providers.settings");
2434                        } catch (Exception e) {
2435                            // Try again later
2436                        }
2437                    }
2438                    break;
2439                case CMD_GET_CONFIGURED_NETWORKS:
2440                    replyToMessage(message, message.what,
2441                            mWifiConfigStore.getConfiguredNetworks());
2442                    break;
2443                    /* Cannot start soft AP while in client mode */
2444                case CMD_START_AP:
2445                    loge("Failed to start soft AP with a running supplicant");
2446                    setWifiApState(WIFI_AP_STATE_FAILED);
2447                    break;
2448                case CMD_SET_SCAN_MODE:
2449                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2450                    break;
2451                case WifiManager.SAVE_NETWORK:
2452                    config = (WifiConfiguration) message.obj;
2453                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2454                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
2455                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
2456                    } else {
2457                        loge("Failed to save network");
2458                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
2459                                WifiManager.ERROR);
2460                    }
2461                    break;
2462                case WifiManager.FORGET_NETWORK:
2463                    if (mWifiConfigStore.forgetNetwork(message.arg1)) {
2464                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
2465                    } else {
2466                        loge("Failed to forget network");
2467                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
2468                                WifiManager.ERROR);
2469                    }
2470                    break;
2471                default:
2472                    return NOT_HANDLED;
2473            }
2474            return HANDLED;
2475        }
2476
2477        @Override
2478        public void exit() {
2479            mNetworkInfo.setIsAvailable(false);
2480        }
2481    }
2482
2483    class SupplicantStoppingState extends State {
2484        @Override
2485        public void enter() {
2486            if (DBG) log(getName() + "\n");
2487            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2488
2489            /* Send any reset commands to supplicant before shutting it down */
2490            handleNetworkDisconnect();
2491
2492            if (DBG) log("stopping supplicant");
2493            if (!mWifiNative.stopSupplicant()) {
2494                loge("Failed to stop supplicant");
2495            }
2496
2497            /* Send ourselves a delayed message to indicate failure after a wait time */
2498            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
2499                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
2500
2501            mNetworkInfo.setIsAvailable(false);
2502            setWifiState(WIFI_STATE_DISABLING);
2503            sendSupplicantConnectionChangedBroadcast(false);
2504            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2505        }
2506        @Override
2507        public boolean processMessage(Message message) {
2508            if (DBG) log(getName() + message.toString() + "\n");
2509            switch(message.what) {
2510                case WifiMonitor.SUP_CONNECTION_EVENT:
2511                    loge("Supplicant connection received while stopping");
2512                    break;
2513                case WifiMonitor.SUP_DISCONNECTION_EVENT:
2514                    if (DBG) log("Supplicant connection lost");
2515                    /* Socket connection can be lost when we do a graceful shutdown
2516                     * or when the driver is hung. Ensure supplicant is stopped here.
2517                     */
2518                    mWifiNative.killSupplicant();
2519                    mWifiNative.closeSupplicantConnection();
2520                    transitionTo(mDriverLoadedState);
2521                    break;
2522                case CMD_STOP_SUPPLICANT_FAILED:
2523                    if (message.arg1 == mSupplicantStopFailureToken) {
2524                        loge("Timed out on a supplicant stop, kill and proceed");
2525                        mWifiNative.killSupplicant();
2526                        mWifiNative.closeSupplicantConnection();
2527                        transitionTo(mDriverLoadedState);
2528                    }
2529                    break;
2530                case CMD_LOAD_DRIVER:
2531                case CMD_UNLOAD_DRIVER:
2532                case CMD_START_SUPPLICANT:
2533                case CMD_STOP_SUPPLICANT:
2534                case CMD_START_AP:
2535                case CMD_STOP_AP:
2536                case CMD_START_DRIVER:
2537                case CMD_STOP_DRIVER:
2538                case CMD_SET_SCAN_MODE:
2539                case CMD_SET_SCAN_TYPE:
2540                case CMD_SET_COUNTRY_CODE:
2541                case CMD_SET_FREQUENCY_BAND:
2542                case CMD_START_PACKET_FILTERING:
2543                case CMD_STOP_PACKET_FILTERING:
2544                    deferMessage(message);
2545                    break;
2546                default:
2547                    return NOT_HANDLED;
2548            }
2549            return HANDLED;
2550        }
2551    }
2552
2553    class DriverStartingState extends State {
2554        private int mTries;
2555        @Override
2556        public void enter() {
2557            if (DBG) log(getName() + "\n");
2558            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2559
2560            mTries = 1;
2561            /* Send ourselves a delayed message to start driver a second time */
2562            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2563                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2564        }
2565        @Override
2566        public boolean processMessage(Message message) {
2567            if (DBG) log(getName() + message.toString() + "\n");
2568            switch(message.what) {
2569               case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2570                    SupplicantState state = handleSupplicantStateChange(message);
2571                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
2572                     * a state that indicates driver has started, it is ready to
2573                     * receive driver commands
2574                     */
2575                    if (SupplicantState.isDriverActive(state)) {
2576                        transitionTo(mDriverStartedState);
2577                    }
2578                    break;
2579                case CMD_DRIVER_START_TIMED_OUT:
2580                    if (message.arg1 == mDriverStartToken) {
2581                        if (mTries >= 2) {
2582                            loge("Failed to start driver after " + mTries);
2583                            transitionTo(mDriverStoppedState);
2584                        } else {
2585                            loge("Driver start failed, retrying");
2586                            mWakeLock.acquire();
2587                            mWifiNative.startDriver();
2588                            mWakeLock.release();
2589
2590                            ++mTries;
2591                            /* Send ourselves a delayed message to start driver again */
2592                            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2593                                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2594                        }
2595                    }
2596                    break;
2597                    /* Queue driver commands & connection events */
2598                case CMD_START_DRIVER:
2599                case CMD_STOP_DRIVER:
2600                case WifiMonitor.NETWORK_CONNECTION_EVENT:
2601                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2602                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2603                case WifiMonitor.WPS_OVERLAP_EVENT:
2604                case CMD_SET_SCAN_TYPE:
2605                case CMD_SET_COUNTRY_CODE:
2606                case CMD_SET_FREQUENCY_BAND:
2607                case CMD_START_PACKET_FILTERING:
2608                case CMD_STOP_PACKET_FILTERING:
2609                case CMD_START_SCAN:
2610                case CMD_DISCONNECT:
2611                case CMD_REASSOCIATE:
2612                case CMD_RECONNECT:
2613                    deferMessage(message);
2614                    break;
2615                default:
2616                    return NOT_HANDLED;
2617            }
2618            return HANDLED;
2619        }
2620    }
2621
2622    class DriverStartedState extends State {
2623        @Override
2624        public void enter() {
2625            if (DBG) log(getName() + "\n");
2626            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2627
2628            mIsRunning = true;
2629            mInDelayedStop = false;
2630            updateBatteryWorkSource(null);
2631
2632            /**
2633             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2634             * When this mode is on, some of the low-level scan parameters used by the
2635             * driver are changed to reduce interference with bluetooth
2636             */
2637            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2638            /* set country code */
2639            setCountryCode();
2640            /* set frequency band of operation */
2641            setFrequencyBand();
2642            /* initialize network state */
2643            setNetworkDetailedState(DetailedState.DISCONNECTED);
2644
2645            /* Remove any filtering on Multicast v6 at start */
2646            mWifiNative.stopFilteringMulticastV6Packets();
2647
2648            /* Reset Multicast v4 filtering state */
2649            if (mFilteringMulticastV4Packets.get()) {
2650                mWifiNative.startFilteringMulticastV4Packets();
2651            } else {
2652                mWifiNative.stopFilteringMulticastV4Packets();
2653            }
2654
2655            mWifiNative.setPowerSave(mPowerSaveEnabled);
2656
2657            if (mIsScanMode) {
2658                mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
2659                mWifiNative.disconnect();
2660                transitionTo(mScanModeState);
2661            } else {
2662                mWifiNative.setScanResultHandling(CONNECT_MODE);
2663                mWifiNative.reconnect();
2664                // Status pulls in the current supplicant state and network connection state
2665                // events over the monitor connection. This helps framework sync up with
2666                // current supplicant state
2667                mWifiNative.status();
2668                transitionTo(mDisconnectedState);
2669            }
2670
2671            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
2672
2673            mContext.registerReceiver(mScreenReceiver, mScreenFilter);
2674        }
2675        @Override
2676        public boolean processMessage(Message message) {
2677            if (DBG) log(getName() + message.toString() + "\n");
2678            switch(message.what) {
2679               case CMD_SET_SCAN_TYPE:
2680                    mSetScanActive = (message.arg1 == SCAN_ACTIVE);
2681                    mWifiNative.setScanMode(mSetScanActive);
2682                    break;
2683                case CMD_START_SCAN:
2684                    boolean forceActive = (message.arg1 == SCAN_ACTIVE);
2685                    if (forceActive && !mSetScanActive) {
2686                        mWifiNative.setScanMode(forceActive);
2687                    }
2688                    mWifiNative.scan();
2689                    if (forceActive && !mSetScanActive) {
2690                        mWifiNative.setScanMode(mSetScanActive);
2691                    }
2692                    mScanResultIsPending = true;
2693                    break;
2694                case CMD_SET_COUNTRY_CODE:
2695                    String country = (String) message.obj;
2696                    if (DBG) log("set country code " + country);
2697                    if (!mWifiNative.setCountryCode(country.toUpperCase())) {
2698                        loge("Failed to set country code " + country);
2699                    }
2700                    break;
2701                case CMD_SET_FREQUENCY_BAND:
2702                    int band =  message.arg1;
2703                    if (DBG) log("set frequency band " + band);
2704                    if (mWifiNative.setBand(band)) {
2705                        mFrequencyBand.set(band);
2706                        //Fetch the latest scan results when frequency band is set
2707                        startScan(true);
2708                    } else {
2709                        loge("Failed to set frequency band " + band);
2710                    }
2711                    break;
2712                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2713                    mBluetoothConnectionActive = (message.arg1 !=
2714                            BluetoothAdapter.STATE_DISCONNECTED);
2715                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2716                    break;
2717                case CMD_STOP_DRIVER:
2718                    int mode = message.arg1;
2719
2720                    /* Already doing a delayed stop && not in ecm state */
2721                    if (mInDelayedStop && mode != IN_ECM_STATE) {
2722                        if (DBG) log("Already in delayed stop");
2723                        break;
2724                    }
2725                    mInDelayedStop = true;
2726                    mDelayedStopCounter++;
2727                    if (DBG) log("Delayed stop message " + mDelayedStopCounter);
2728
2729                    if (mode == IN_ECM_STATE) {
2730                        /* send a shut down immediately */
2731                        sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
2732                    } else {
2733                        /* send regular delayed shut down */
2734                        Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
2735                        driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
2736                        mDriverStopIntent = PendingIntent.getBroadcast(mContext,
2737                                DRIVER_STOP_REQUEST, driverStopIntent,
2738                                PendingIntent.FLAG_UPDATE_CURRENT);
2739
2740                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
2741                                + mDriverStopDelayMs, mDriverStopIntent);
2742                    }
2743                    break;
2744                case CMD_START_DRIVER:
2745                    if (mInDelayedStop) {
2746                        mInDelayedStop = false;
2747                        mDelayedStopCounter++;
2748                        mAlarmManager.cancel(mDriverStopIntent);
2749                        if (DBG) log("Delayed stop ignored due to start");
2750                    }
2751                    break;
2752                case CMD_DELAYED_STOP_DRIVER:
2753                    if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
2754                    if (message.arg1 != mDelayedStopCounter) break;
2755                    if (getCurrentState() != mDisconnectedState) {
2756                        mWifiNative.disconnect();
2757                        handleNetworkDisconnect();
2758                    }
2759                    mWakeLock.acquire();
2760                    mWifiNative.stopDriver();
2761                    transitionTo(mDriverStoppingState);
2762                    mWakeLock.release();
2763                    break;
2764                case CMD_START_PACKET_FILTERING:
2765                    if (message.arg1 == MULTICAST_V6) {
2766                        mWifiNative.startFilteringMulticastV6Packets();
2767                    } else if (message.arg1 == MULTICAST_V4) {
2768                        mWifiNative.startFilteringMulticastV4Packets();
2769                    } else {
2770                        loge("Illegal arugments to CMD_START_PACKET_FILTERING");
2771                    }
2772                    break;
2773                case CMD_STOP_PACKET_FILTERING:
2774                    if (message.arg1 == MULTICAST_V6) {
2775                        mWifiNative.stopFilteringMulticastV6Packets();
2776                    } else if (message.arg1 == MULTICAST_V4) {
2777                        mWifiNative.stopFilteringMulticastV4Packets();
2778                    } else {
2779                        loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
2780                    }
2781                    break;
2782                case CMD_SET_SUSPEND_OPTIMIZATIONS:
2783                    if (!mHighPerfMode) {
2784                        mWifiNative.setSuspendOptimizations(true);
2785                    }
2786                    mSuspendWakeLock.release();
2787                    break;
2788                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
2789                    mWifiNative.setSuspendOptimizations(false);
2790                    break;
2791                case CMD_SET_HIGH_PERF_MODE:
2792                    mHighPerfMode = (message.arg1 == 1);
2793                    if (mHighPerfMode) {
2794                        //Disable any suspend optimizations
2795                        mWifiNative.setSuspendOptimizations(false);
2796                    }
2797                    break;
2798                default:
2799                    return NOT_HANDLED;
2800            }
2801            return HANDLED;
2802        }
2803        @Override
2804        public void exit() {
2805            if (DBG) log(getName() + "\n");
2806            mIsRunning = false;
2807            updateBatteryWorkSource(null);
2808            mScanResults = new ArrayList<ScanResult>();
2809
2810            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
2811            mContext.unregisterReceiver(mScreenReceiver);
2812        }
2813    }
2814
2815    class DriverStoppingState extends State {
2816        @Override
2817        public void enter() {
2818            if (DBG) log(getName() + "\n");
2819            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2820        }
2821        @Override
2822        public boolean processMessage(Message message) {
2823            if (DBG) log(getName() + message.toString() + "\n");
2824            switch(message.what) {
2825                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2826                    SupplicantState state = handleSupplicantStateChange(message);
2827                    if (state == SupplicantState.INTERFACE_DISABLED) {
2828                        transitionTo(mDriverStoppedState);
2829                    }
2830                    break;
2831                    /* Queue driver commands */
2832                case CMD_START_DRIVER:
2833                case CMD_STOP_DRIVER:
2834                case CMD_SET_SCAN_TYPE:
2835                case CMD_SET_COUNTRY_CODE:
2836                case CMD_SET_FREQUENCY_BAND:
2837                case CMD_START_PACKET_FILTERING:
2838                case CMD_STOP_PACKET_FILTERING:
2839                case CMD_START_SCAN:
2840                case CMD_DISCONNECT:
2841                case CMD_REASSOCIATE:
2842                case CMD_RECONNECT:
2843                    deferMessage(message);
2844                    break;
2845                default:
2846                    return NOT_HANDLED;
2847            }
2848            return HANDLED;
2849        }
2850    }
2851
2852    class DriverStoppedState extends State {
2853        @Override
2854        public void enter() {
2855            if (DBG) log(getName() + "\n");
2856            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2857        }
2858        @Override
2859        public boolean processMessage(Message message) {
2860            if (DBG) log(getName() + message.toString() + "\n");
2861            switch (message.what) {
2862                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2863                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2864                    SupplicantState state = stateChangeResult.state;
2865                    // A WEXT bug means that we can be back to driver started state
2866                    // unexpectedly
2867                    if (SupplicantState.isDriverActive(state)) {
2868                        transitionTo(mDriverStartedState);
2869                    }
2870                    break;
2871                case CMD_START_DRIVER:
2872                    mWakeLock.acquire();
2873                    mWifiNative.startDriver();
2874                    mWakeLock.release();
2875                    transitionTo(mDriverStartingState);
2876                    break;
2877                default:
2878                    return NOT_HANDLED;
2879            }
2880            return HANDLED;
2881        }
2882    }
2883
2884    class ScanModeState extends State {
2885        @Override
2886        public void enter() {
2887            if (DBG) log(getName() + "\n");
2888            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2889        }
2890        @Override
2891        public boolean processMessage(Message message) {
2892            if (DBG) log(getName() + message.toString() + "\n");
2893            switch(message.what) {
2894                case CMD_SET_SCAN_MODE:
2895                    if (message.arg1 == SCAN_ONLY_MODE) {
2896                        /* Ignore */
2897                        return HANDLED;
2898                    } else {
2899                        mWifiNative.setScanResultHandling(message.arg1);
2900                        mWifiNative.reconnect();
2901                        mIsScanMode = false;
2902                        transitionTo(mDisconnectedState);
2903                    }
2904                    break;
2905                    /* Ignore */
2906                case CMD_DISCONNECT:
2907                case CMD_RECONNECT:
2908                case CMD_REASSOCIATE:
2909                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2910                case WifiMonitor.NETWORK_CONNECTION_EVENT:
2911                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2912                    break;
2913                default:
2914                    return NOT_HANDLED;
2915            }
2916            return HANDLED;
2917        }
2918    }
2919
2920    class ConnectModeState extends State {
2921        @Override
2922        public void enter() {
2923            if (DBG) log(getName() + "\n");
2924            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2925        }
2926        @Override
2927        public boolean processMessage(Message message) {
2928            if (DBG) log(getName() + message.toString() + "\n");
2929            StateChangeResult stateChangeResult;
2930            switch(message.what) {
2931                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2932                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
2933                    break;
2934                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2935                    SupplicantState state = handleSupplicantStateChange(message);
2936                    // A driver/firmware hang can now put the interface in a down state.
2937                    // We detect the interface going down and recover from it
2938                    if (!SupplicantState.isDriverActive(state)) {
2939                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2940                            handleNetworkDisconnect();
2941                        }
2942                        log("Detected an interface down, restart driver");
2943                        transitionTo(mDriverStoppedState);
2944                        sendMessage(CMD_START_DRIVER);
2945                        break;
2946                    }
2947
2948                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
2949                    // when authentication times out after a successful connection,
2950                    // we can figure this from the supplicant state. If supplicant
2951                    // state is DISCONNECTED, but the mNetworkInfo says we are not
2952                    // disconnected, we need to handle a disconnection
2953                    if (state == SupplicantState.DISCONNECTED &&
2954                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2955                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
2956                        handleNetworkDisconnect();
2957                        transitionTo(mDisconnectedState);
2958                    }
2959                    break;
2960                    /* Do a redundant disconnect without transition */
2961                case CMD_DISCONNECT:
2962                    mWifiNative.disconnect();
2963                    break;
2964                case CMD_RECONNECT:
2965                    mWifiNative.reconnect();
2966                    break;
2967                case CMD_REASSOCIATE:
2968                    mWifiNative.reassociate();
2969                    break;
2970                case WifiManager.CONNECT_NETWORK:
2971                    /* The connect message can contain a network id passed as arg1 on message or
2972                     * or a config passed as obj on message.
2973                     * For a new network, a config is passed to create and connect.
2974                     * For an existing network, a network id is passed
2975                     */
2976                    int netId = message.arg1;
2977                    WifiConfiguration config = (WifiConfiguration) message.obj;
2978
2979                    /* Save the network config */
2980                    if (config != null) {
2981                        NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2982                        netId = result.getNetworkId();
2983                    }
2984
2985                    if (mWifiConfigStore.selectNetwork(netId) &&
2986                            mWifiNative.reconnect()) {
2987                        /* The state tracker handles enabling networks upon completion/failure */
2988                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
2989                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
2990                        /* Expect a disconnection from the old connection */
2991                        transitionTo(mDisconnectingState);
2992                    } else {
2993                        loge("Failed to connect config: " + config + " netId: " + netId);
2994                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
2995                                WifiManager.ERROR);
2996                        break;
2997                    }
2998                    break;
2999                case WifiManager.START_WPS:
3000                    WpsInfo wpsInfo = (WpsInfo) message.obj;
3001                    WpsResult result;
3002                    switch (wpsInfo.setup) {
3003                        case WpsInfo.PBC:
3004                            result = mWifiConfigStore.startWpsPbc(wpsInfo);
3005                            break;
3006                        case WpsInfo.KEYPAD:
3007                            result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
3008                            break;
3009                        case WpsInfo.DISPLAY:
3010                            result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
3011                            break;
3012                        default:
3013                            result = new WpsResult(Status.FAILURE);
3014                            Log.e(TAG, "Invalid setup for WPS");
3015                            break;
3016                    }
3017                    if (result.status == Status.SUCCESS) {
3018                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result);
3019                        transitionTo(mWpsRunningState);
3020                    } else {
3021                        Log.e(TAG, "Failed to start WPS with config " + wpsInfo.toString());
3022                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
3023                    }
3024                    break;
3025                case WifiMonitor.SCAN_RESULTS_EVENT:
3026                    /* Set the scan setting back to "connect" mode */
3027                    mWifiNative.setScanResultHandling(CONNECT_MODE);
3028                    /* Handle scan results */
3029                    return NOT_HANDLED;
3030                case WifiMonitor.NETWORK_CONNECTION_EVENT:
3031                    if (DBG) log("Network connection established");
3032                    mLastNetworkId = message.arg1;
3033                    mLastBssid = (String) message.obj;
3034
3035                    mWifiInfo.setBSSID(mLastBssid);
3036                    mWifiInfo.setNetworkId(mLastNetworkId);
3037                    /* send event to CM & network change broadcast */
3038                    setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
3039                    sendNetworkStateChangeBroadcast(mLastBssid);
3040                    transitionTo(mObtainingIpState);
3041                    break;
3042                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3043                    if (DBG) log("Network connection lost");
3044                    handleNetworkDisconnect();
3045                    transitionTo(mDisconnectedState);
3046                    break;
3047                default:
3048                    return NOT_HANDLED;
3049            }
3050            return HANDLED;
3051        }
3052    }
3053
3054    class L2ConnectedState extends State {
3055        @Override
3056        public void enter() {
3057            if (DBG) log(getName() + "\n");
3058            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3059            mRssiPollToken++;
3060            if (mEnableRssiPolling) {
3061                sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0));
3062            }
3063        }
3064
3065        @Override
3066        public boolean processMessage(Message message) {
3067            if (DBG) log(getName() + message.toString() + "\n");
3068            switch (message.what) {
3069              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
3070                  handlePreDhcpSetup();
3071                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
3072                  break;
3073              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
3074                  handlePostDhcpSetup();
3075                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
3076                      if (DBG) log("DHCP successful");
3077                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
3078                      transitionTo(mVerifyingLinkState);
3079                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
3080                      if (DBG) log("DHCP failed");
3081                      handleFailedIpConfiguration();
3082                      transitionTo(mDisconnectingState);
3083                  }
3084                  break;
3085                case CMD_DISCONNECT:
3086                    mWifiNative.disconnect();
3087                    transitionTo(mDisconnectingState);
3088                    break;
3089                case CMD_SET_SCAN_MODE:
3090                    if (message.arg1 == SCAN_ONLY_MODE) {
3091                        sendMessage(CMD_DISCONNECT);
3092                        deferMessage(message);
3093                    }
3094                    break;
3095                case CMD_START_SCAN:
3096                    /* When the network is connected, re-scanning can trigger
3097                     * a reconnection. Put it in scan-only mode during scan.
3098                     * When scan results are received, the mode is switched
3099                     * back to CONNECT_MODE.
3100                     */
3101                    mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
3102                    /* Have the parent state handle the rest */
3103                    return NOT_HANDLED;
3104                    /* Ignore connection to same network */
3105                case WifiManager.CONNECT_NETWORK:
3106                    int netId = message.arg1;
3107                    if (mWifiInfo.getNetworkId() == netId) {
3108                        break;
3109                    }
3110                    return NOT_HANDLED;
3111                case WifiManager.SAVE_NETWORK:
3112                    WifiConfiguration config = (WifiConfiguration) message.obj;
3113                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3114                    if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
3115                        if (result.hasIpChanged()) {
3116                            log("Reconfiguring IP on connection");
3117                            transitionTo(mObtainingIpState);
3118                        }
3119                        if (result.hasProxyChanged()) {
3120                            log("Reconfiguring proxy on connection");
3121                            configureLinkProperties();
3122                            sendLinkConfigurationChangedBroadcast();
3123                        }
3124                    }
3125
3126                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
3127                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
3128                    } else {
3129                        loge("Failed to save network");
3130                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3131                                WifiManager.ERROR);
3132                    }
3133                    break;
3134                    /* Ignore */
3135                case WifiMonitor.NETWORK_CONNECTION_EVENT:
3136                    break;
3137                case CMD_RSSI_POLL:
3138                    if (message.arg1 == mRssiPollToken) {
3139                        // Get Info and continue polling
3140                        fetchRssiAndLinkSpeedNative();
3141                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3142                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3143                    } else {
3144                        // Polling has completed
3145                    }
3146                    break;
3147                case CMD_ENABLE_RSSI_POLL:
3148                    mEnableRssiPolling = (message.arg1 == 1);
3149                    mRssiPollToken++;
3150                    if (mEnableRssiPolling) {
3151                        // first poll
3152                        fetchRssiAndLinkSpeedNative();
3153                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3154                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3155                    }
3156                    break;
3157                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
3158                    RssiPktcntStat stat = (RssiPktcntStat) message.obj;
3159                    fetchRssiAndLinkSpeedNative();
3160                    stat.rssi = mWifiInfo.getRssi();
3161                    fetchPktcntNative(stat);
3162                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_SUCCEEDED,
3163                            stat);
3164                    break;
3165                default:
3166                    return NOT_HANDLED;
3167            }
3168
3169            return HANDLED;
3170        }
3171
3172        @Override
3173        public void exit() {
3174            /* If a scan result is pending in connected state, the supplicant
3175             * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
3176             */
3177            if (mScanResultIsPending) {
3178                mWifiNative.setScanResultHandling(CONNECT_MODE);
3179            }
3180        }
3181    }
3182
3183    class ObtainingIpState extends State {
3184        @Override
3185        public void enter() {
3186            if (DBG) log(getName() + "\n");
3187            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3188
3189            if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
3190                //start DHCP
3191                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
3192                        mContext, WifiStateMachine.this, mInterfaceName);
3193                mDhcpStateMachine.registerForPreDhcpNotification();
3194                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
3195            } else {
3196                DhcpInfoInternal dhcpInfoInternal = mWifiConfigStore.getIpConfiguration(
3197                        mLastNetworkId);
3198                InterfaceConfiguration ifcg = new InterfaceConfiguration();
3199                ifcg.setLinkAddress(dhcpInfoInternal.makeLinkAddress());
3200                ifcg.setInterfaceUp();
3201                try {
3202                    mNwService.setInterfaceConfig(mInterfaceName, ifcg);
3203                    if (DBG) log("Static IP configuration succeeded");
3204                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
3205                } catch (RemoteException re) {
3206                    loge("Static IP configuration failed: " + re);
3207                    sendMessage(CMD_STATIC_IP_FAILURE);
3208                } catch (IllegalStateException e) {
3209                    loge("Static IP configuration failed: " + e);
3210                    sendMessage(CMD_STATIC_IP_FAILURE);
3211                }
3212            }
3213        }
3214      @Override
3215      public boolean processMessage(Message message) {
3216          if (DBG) log(getName() + message.toString() + "\n");
3217          switch(message.what) {
3218            case CMD_STATIC_IP_SUCCESS:
3219                  handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
3220                  transitionTo(mVerifyingLinkState);
3221                  break;
3222              case CMD_STATIC_IP_FAILURE:
3223                  handleFailedIpConfiguration();
3224                  transitionTo(mDisconnectingState);
3225                  break;
3226             case WifiManager.SAVE_NETWORK:
3227                  deferMessage(message);
3228                  break;
3229                  /* Defer any power mode changes since we must keep active power mode at DHCP */
3230              case CMD_SET_HIGH_PERF_MODE:
3231                  deferMessage(message);
3232                  break;
3233              default:
3234                  return NOT_HANDLED;
3235          }
3236          return HANDLED;
3237      }
3238    }
3239
3240    class VerifyingLinkState extends State {
3241        @Override
3242        public void enter() {
3243            if (DBG) log(getName() + "\n");
3244            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3245            setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
3246            mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
3247            sendNetworkStateChangeBroadcast(mLastBssid);
3248        }
3249        @Override
3250        public boolean processMessage(Message message) {
3251            switch (message.what) {
3252                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3253                    //stay here
3254                    break;
3255                case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
3256                    try {
3257                        mNwService.enableIpv6(mInterfaceName);
3258                    } catch (RemoteException re) {
3259                        loge("Failed to enable IPv6: " + re);
3260                    } catch (IllegalStateException e) {
3261                        loge("Failed to enable IPv6: " + e);
3262                    }
3263
3264                    setNetworkDetailedState(DetailedState.CONNECTED);
3265                    mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
3266                    sendNetworkStateChangeBroadcast(mLastBssid);
3267                    transitionTo(mConnectedState);
3268                    break;
3269                default:
3270                    return NOT_HANDLED;
3271            }
3272            return HANDLED;
3273        }
3274    }
3275
3276    class ConnectedState extends State {
3277        @Override
3278        public void enter() {
3279            if (DBG) log(getName() + "\n");
3280            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3281       }
3282        @Override
3283        public boolean processMessage(Message message) {
3284            if (DBG) log(getName() + message.toString() + "\n");
3285            switch (message.what) {
3286               case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3287                    if (DBG) log("Watchdog reports poor link");
3288                    try {
3289                        mNwService.disableIpv6(mInterfaceName);
3290                    } catch (RemoteException re) {
3291                        loge("Failed to disable IPv6: " + re);
3292                    } catch (IllegalStateException e) {
3293                        loge("Failed to disable IPv6: " + e);
3294                    }
3295                    /* Report a disconnect */
3296                    setNetworkDetailedState(DetailedState.DISCONNECTED);
3297                    mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
3298                    sendNetworkStateChangeBroadcast(mLastBssid);
3299
3300                    transitionTo(mVerifyingLinkState);
3301                    break;
3302                default:
3303                    return NOT_HANDLED;
3304            }
3305            return HANDLED;
3306        }
3307        @Override
3308        public void exit() {
3309            /* Request a CS wakelock during transition to mobile */
3310            checkAndSetConnectivityInstance();
3311            mCm.requestNetworkTransitionWakelock(TAG);
3312        }
3313    }
3314
3315    class DisconnectingState extends State {
3316        @Override
3317        public void enter() {
3318            if (DBG) log(getName() + "\n");
3319            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3320        }
3321        @Override
3322        public boolean processMessage(Message message) {
3323            if (DBG) log(getName() + message.toString() + "\n");
3324            switch (message.what) {
3325                case CMD_SET_SCAN_MODE:
3326                    if (message.arg1 == SCAN_ONLY_MODE) {
3327                        deferMessage(message);
3328                    }
3329                    break;
3330                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3331                    /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
3332                     * we have missed the network disconnection, transition to mDisconnectedState
3333                     * and handle the rest of the events there
3334                     */
3335                    deferMessage(message);
3336                    handleNetworkDisconnect();
3337                    transitionTo(mDisconnectedState);
3338                    break;
3339                default:
3340                    return NOT_HANDLED;
3341            }
3342            return HANDLED;
3343        }
3344    }
3345
3346    class DisconnectedState extends State {
3347        private boolean mAlarmEnabled = false;
3348        /* This is set from the overlay config file or from a secure setting.
3349         * A value of 0 disables scanning in the framework.
3350         */
3351        private long mFrameworkScanIntervalMs;
3352
3353        private void setScanAlarm(boolean enabled) {
3354            if (enabled == mAlarmEnabled) return;
3355            if (enabled) {
3356                if (mFrameworkScanIntervalMs > 0) {
3357                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
3358                            System.currentTimeMillis() + mFrameworkScanIntervalMs,
3359                            mFrameworkScanIntervalMs,
3360                            mScanIntent);
3361                    mAlarmEnabled = true;
3362                }
3363            } else {
3364                mAlarmManager.cancel(mScanIntent);
3365                mAlarmEnabled = false;
3366            }
3367        }
3368
3369        @Override
3370        public void enter() {
3371            if (DBG) log(getName() + "\n");
3372            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3373
3374            mFrameworkScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
3375                    Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
3376                    mDefaultFrameworkScanIntervalMs);
3377            /*
3378             * We initiate background scanning if it is enabled, otherwise we
3379             * initiate an infrequent scan that wakes up the device to ensure
3380             * a user connects to an access point on the move
3381             */
3382            if (mEnableBackgroundScan) {
3383                /* If a regular scan result is pending, do not initiate background
3384                 * scan until the scan results are returned. This is needed because
3385                 * initiating a background scan will cancel the regular scan and
3386                 * scan results will not be returned until background scanning is
3387                 * cleared
3388                 */
3389                if (!mScanResultIsPending) {
3390                    mWifiNative.enableBackgroundScan(true);
3391                }
3392            } else {
3393                setScanAlarm(true);
3394            }
3395
3396            /**
3397             * If we have no networks saved, the supplicant stops doing the periodic scan.
3398             * The scans are useful to notify the user of the presence of an open network.
3399             * Note that these are not wake up scans.
3400             */
3401            if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3402                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3403                            ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3404            }
3405        }
3406        @Override
3407        public boolean processMessage(Message message) {
3408            if (DBG) log(getName() + message.toString() + "\n");
3409            boolean ret = HANDLED;
3410            switch (message.what) {
3411                case CMD_NO_NETWORKS_PERIODIC_SCAN:
3412                    if (message.arg1 == mPeriodicScanToken &&
3413                            mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3414                        sendMessage(CMD_START_SCAN);
3415                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3416                                    ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3417                    }
3418                    break;
3419                case WifiManager.FORGET_NETWORK:
3420                case CMD_REMOVE_NETWORK:
3421                    // Set up a delayed message here. After the forget/remove is handled
3422                    // the handled delayed message will determine if there is a need to
3423                    // scan and continue
3424                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3425                                ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3426                    ret = NOT_HANDLED;
3427                    break;
3428                case CMD_SET_SCAN_MODE:
3429                    if (message.arg1 == SCAN_ONLY_MODE) {
3430                        mWifiNative.setScanResultHandling(message.arg1);
3431                        //Supplicant disconnect to prevent further connects
3432                        mWifiNative.disconnect();
3433                        mIsScanMode = true;
3434                        transitionTo(mScanModeState);
3435                    }
3436                    break;
3437                case CMD_ENABLE_BACKGROUND_SCAN:
3438                    mEnableBackgroundScan = (message.arg1 == 1);
3439                    if (mEnableBackgroundScan) {
3440                        mWifiNative.enableBackgroundScan(true);
3441                        setScanAlarm(false);
3442                    } else {
3443                        mWifiNative.enableBackgroundScan(false);
3444                        setScanAlarm(true);
3445                    }
3446                    break;
3447                    /* Ignore network disconnect */
3448                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3449                    break;
3450                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3451                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3452                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
3453                    /* ConnectModeState does the rest of the handling */
3454                    ret = NOT_HANDLED;
3455                    break;
3456                case CMD_START_SCAN:
3457                    /* Disable background scan temporarily during a regular scan */
3458                    if (mEnableBackgroundScan) {
3459                        mWifiNative.enableBackgroundScan(false);
3460                    }
3461                    /* Handled in parent state */
3462                    ret = NOT_HANDLED;
3463                    break;
3464                case WifiMonitor.SCAN_RESULTS_EVENT:
3465                    /* Re-enable background scan when a pending scan result is received */
3466                    if (mEnableBackgroundScan && mScanResultIsPending) {
3467                        mWifiNative.enableBackgroundScan(true);
3468                    }
3469                    /* Handled in parent state */
3470                    ret = NOT_HANDLED;
3471                    break;
3472                default:
3473                    ret = NOT_HANDLED;
3474            }
3475            return ret;
3476        }
3477
3478        @Override
3479        public void exit() {
3480            /* No need for a background scan upon exit from a disconnected state */
3481            if (mEnableBackgroundScan) {
3482                mWifiNative.enableBackgroundScan(false);
3483            }
3484            setScanAlarm(false);
3485        }
3486    }
3487
3488    class WpsRunningState extends State {
3489        //Tracks the source to provide a reply
3490        private Message mSourceMessage;
3491        @Override
3492        public void enter() {
3493            if (DBG) log(getName() + "\n");
3494            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3495            mSourceMessage = Message.obtain(getCurrentMessage());
3496        }
3497        @Override
3498        public boolean processMessage(Message message) {
3499            if (DBG) log(getName() + message.toString() + "\n");
3500            switch (message.what) {
3501                case WifiMonitor.WPS_SUCCESS_EVENT:
3502                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
3503                    mSourceMessage.recycle();
3504                    mSourceMessage = null;
3505                    transitionTo(mDisconnectedState);
3506                    break;
3507                case WifiMonitor.WPS_OVERLAP_EVENT:
3508                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3509                            WifiManager.WPS_OVERLAP_ERROR);
3510                    mSourceMessage.recycle();
3511                    mSourceMessage = null;
3512                    transitionTo(mDisconnectedState);
3513                    break;
3514                case WifiMonitor.WPS_FAIL_EVENT:
3515                    //arg1 has the reason for the failure
3516                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
3517                    mSourceMessage.recycle();
3518                    mSourceMessage = null;
3519                    transitionTo(mDisconnectedState);
3520                    break;
3521                case WifiMonitor.WPS_TIMEOUT_EVENT:
3522                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3523                            WifiManager.WPS_TIMED_OUT);
3524                    mSourceMessage.recycle();
3525                    mSourceMessage = null;
3526                    transitionTo(mDisconnectedState);
3527                    break;
3528                case WifiManager.START_WPS:
3529                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
3530                    break;
3531                case WifiManager.CANCEL_WPS:
3532                    if (mWifiNative.cancelWps()) {
3533                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
3534                    } else {
3535                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
3536                    }
3537                    transitionTo(mDisconnectedState);
3538                    break;
3539                /* Defer all commands that can cause connections to a different network
3540                 * or put the state machine out of connect mode
3541                 */
3542                case CMD_STOP_DRIVER:
3543                case CMD_SET_SCAN_MODE:
3544                case WifiManager.CONNECT_NETWORK:
3545                case CMD_ENABLE_NETWORK:
3546                case CMD_RECONNECT:
3547                case CMD_REASSOCIATE:
3548                case WifiMonitor.NETWORK_CONNECTION_EVENT: /* Handled after exiting WPS state */
3549                    deferMessage(message);
3550                    break;
3551                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3552                    if (DBG) log("Network connection lost");
3553                    handleNetworkDisconnect();
3554                    break;
3555                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3556                    // EAP failures do not mean much during WPS
3557                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3558                    //Throw away supplicant state changes when WPS is running.
3559                    //We will start getting supplicant state changes once we get
3560                    //a WPS success or failure
3561                    break;
3562                default:
3563                    return NOT_HANDLED;
3564            }
3565            return HANDLED;
3566        }
3567
3568        @Override
3569        public void exit() {
3570            mWifiConfigStore.enableAllNetworks();
3571            mWifiConfigStore.loadConfiguredNetworks();
3572        }
3573    }
3574
3575    class SoftApStartingState extends State {
3576        @Override
3577        public void enter() {
3578            if (DBG) log(getName() + "\n");
3579            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3580
3581            final Message message = getCurrentMessage();
3582            if (message.what == CMD_START_AP) {
3583                final WifiConfiguration config = (WifiConfiguration) message.obj;
3584
3585                if (config == null) {
3586                    mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
3587                } else {
3588                    mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
3589                    startSoftApWithConfig(config);
3590                }
3591            } else {
3592                throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
3593            }
3594        }
3595        @Override
3596        public boolean processMessage(Message message) {
3597            if (DBG) log(getName() + message.toString() + "\n");
3598            switch(message.what) {
3599                case CMD_LOAD_DRIVER:
3600                case CMD_UNLOAD_DRIVER:
3601                case CMD_START_SUPPLICANT:
3602                case CMD_STOP_SUPPLICANT:
3603                case CMD_START_AP:
3604                case CMD_STOP_AP:
3605                case CMD_START_DRIVER:
3606                case CMD_STOP_DRIVER:
3607                case CMD_SET_SCAN_MODE:
3608                case CMD_SET_SCAN_TYPE:
3609                case CMD_SET_COUNTRY_CODE:
3610                case CMD_SET_FREQUENCY_BAND:
3611                case CMD_START_PACKET_FILTERING:
3612                case CMD_STOP_PACKET_FILTERING:
3613                case CMD_TETHER_STATE_CHANGE:
3614                    deferMessage(message);
3615                    break;
3616                case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
3617                    WifiConfiguration config = (WifiConfiguration) message.obj;
3618                    if (config != null) {
3619                        startSoftApWithConfig(config);
3620                    } else {
3621                        loge("Softap config is null!");
3622                        sendMessage(CMD_START_AP_FAILURE);
3623                    }
3624                    break;
3625                case CMD_START_AP_SUCCESS:
3626                    setWifiApState(WIFI_AP_STATE_ENABLED);
3627                    transitionTo(mSoftApStartedState);
3628                    break;
3629                case CMD_START_AP_FAILURE:
3630                    // initiate driver unload
3631                    sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
3632                    break;
3633                default:
3634                    return NOT_HANDLED;
3635            }
3636            return HANDLED;
3637        }
3638    }
3639
3640    class SoftApStartedState extends State {
3641        @Override
3642        public void enter() {
3643            if (DBG) log(getName() + "\n");
3644            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3645        }
3646        @Override
3647        public boolean processMessage(Message message) {
3648            if (DBG) log(getName() + message.toString() + "\n");
3649            switch(message.what) {
3650                case CMD_STOP_AP:
3651                    if (DBG) log("Stopping Soft AP");
3652                    setWifiApState(WIFI_AP_STATE_DISABLING);
3653
3654                    /* We have not tethered at this point, so we just shutdown soft Ap */
3655                    try {
3656                        mNwService.stopAccessPoint(mInterfaceName);
3657                    } catch(Exception e) {
3658                        loge("Exception in stopAccessPoint()");
3659                    }
3660                    transitionTo(mDriverLoadedState);
3661                    break;
3662                case CMD_START_AP:
3663                    // Ignore a start on a running access point
3664                    break;
3665                    /* Fail client mode operation when soft AP is enabled */
3666                case CMD_START_SUPPLICANT:
3667                   loge("Cannot start supplicant with a running soft AP");
3668                    setWifiState(WIFI_STATE_UNKNOWN);
3669                    break;
3670                case CMD_TETHER_STATE_CHANGE:
3671                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3672                    if (startTethering(stateChange.available)) {
3673                        transitionTo(mTetheringState);
3674                    }
3675                    break;
3676                default:
3677                    return NOT_HANDLED;
3678            }
3679            return HANDLED;
3680        }
3681    }
3682
3683    class TetheringState extends State {
3684        @Override
3685        public void enter() {
3686            if (DBG) log(getName() + "\n");
3687            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3688
3689            /* Send ourselves a delayed message to shut down if tethering fails to notify */
3690            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3691                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3692        }
3693        @Override
3694        public boolean processMessage(Message message) {
3695            if (DBG) log(getName() + message.toString() + "\n");
3696            switch(message.what) {
3697                case CMD_TETHER_STATE_CHANGE:
3698                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3699                    if (isWifiTethered(stateChange.active)) {
3700                        transitionTo(mTetheredState);
3701                    }
3702                    return HANDLED;
3703                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3704                    if (message.arg1 == mTetherToken) {
3705                        loge("Failed to get tether update, shutdown soft access point");
3706                        setWifiApEnabled(null, false);
3707                    }
3708                    break;
3709                case CMD_LOAD_DRIVER:
3710                case CMD_UNLOAD_DRIVER:
3711                case CMD_START_SUPPLICANT:
3712                case CMD_STOP_SUPPLICANT:
3713                case CMD_START_AP:
3714                case CMD_STOP_AP:
3715                case CMD_START_DRIVER:
3716                case CMD_STOP_DRIVER:
3717                case CMD_SET_SCAN_MODE:
3718                case CMD_SET_SCAN_TYPE:
3719                case CMD_SET_COUNTRY_CODE:
3720                case CMD_SET_FREQUENCY_BAND:
3721                case CMD_START_PACKET_FILTERING:
3722                case CMD_STOP_PACKET_FILTERING:
3723                    deferMessage(message);
3724                    break;
3725                default:
3726                    return NOT_HANDLED;
3727            }
3728            return HANDLED;
3729        }
3730    }
3731
3732    class TetheredState extends State {
3733        @Override
3734        public void enter() {
3735            if (DBG) log(getName() + "\n");
3736            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3737        }
3738        @Override
3739        public boolean processMessage(Message message) {
3740            if (DBG) log(getName() + message.toString() + "\n");
3741            switch(message.what) {
3742                case CMD_TETHER_STATE_CHANGE:
3743                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3744                    if (!isWifiTethered(stateChange.active)) {
3745                        loge("Tethering reports wifi as untethered!, shut down soft Ap");
3746                        setWifiApEnabled(null, false);
3747                    }
3748                    return HANDLED;
3749                case CMD_STOP_AP:
3750                    if (DBG) log("Untethering before stopping AP");
3751                    setWifiApState(WIFI_AP_STATE_DISABLING);
3752                    stopTethering();
3753                    transitionTo(mSoftApStoppingState);
3754                    break;
3755                default:
3756                    return NOT_HANDLED;
3757            }
3758            return HANDLED;
3759        }
3760    }
3761
3762    class SoftApStoppingState extends State {
3763        @Override
3764        public void enter() {
3765            if (DBG) log(getName() + "\n");
3766            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3767
3768            /* Send ourselves a delayed message to shut down if tethering fails to notify */
3769            sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3770                    ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3771
3772        }
3773        @Override
3774        public boolean processMessage(Message message) {
3775            if (DBG) log(getName() + message.toString() + "\n");
3776            switch(message.what) {
3777                case CMD_TETHER_STATE_CHANGE:
3778                    TetherStateChange stateChange = (TetherStateChange) message.obj;
3779
3780                    /* Wait till wifi is untethered */
3781                    if (isWifiTethered(stateChange.active)) break;
3782
3783                    try {
3784                        mNwService.stopAccessPoint(mInterfaceName);
3785                    } catch(Exception e) {
3786                        loge("Exception in stopAccessPoint()");
3787                    }
3788                    transitionTo(mDriverLoadedState);
3789                    break;
3790                case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3791                    if (message.arg1 == mTetherToken) {
3792                        loge("Failed to get tether update, force stop access point");
3793                        try {
3794                            mNwService.stopAccessPoint(mInterfaceName);
3795                        } catch(Exception e) {
3796                            loge("Exception in stopAccessPoint()");
3797                        }
3798                        transitionTo(mDriverLoadedState);
3799                    }
3800                    break;
3801                case CMD_LOAD_DRIVER:
3802                case CMD_UNLOAD_DRIVER:
3803                case CMD_START_SUPPLICANT:
3804                case CMD_STOP_SUPPLICANT:
3805                case CMD_START_AP:
3806                case CMD_STOP_AP:
3807                case CMD_START_DRIVER:
3808                case CMD_STOP_DRIVER:
3809                case CMD_SET_SCAN_MODE:
3810                case CMD_SET_SCAN_TYPE:
3811                case CMD_SET_COUNTRY_CODE:
3812                case CMD_SET_FREQUENCY_BAND:
3813                case CMD_START_PACKET_FILTERING:
3814                case CMD_STOP_PACKET_FILTERING:
3815                    deferMessage(message);
3816                    break;
3817                default:
3818                    return NOT_HANDLED;
3819            }
3820            return HANDLED;
3821        }
3822    }
3823
3824    //State machine initiated requests can have replyTo set to null indicating
3825    //there are no recepients, we ignore those reply actions
3826    private void replyToMessage(Message msg, int what) {
3827        if (msg.replyTo == null) return;
3828        Message dstMsg = obtainMessageWithArg2(msg);
3829        dstMsg.what = what;
3830        mReplyChannel.replyToMessage(msg, dstMsg);
3831    }
3832
3833    private void replyToMessage(Message msg, int what, int arg1) {
3834        if (msg.replyTo == null) return;
3835        Message dstMsg = obtainMessageWithArg2(msg);
3836        dstMsg.what = what;
3837        dstMsg.arg1 = arg1;
3838        mReplyChannel.replyToMessage(msg, dstMsg);
3839    }
3840
3841    private void replyToMessage(Message msg, int what, Object obj) {
3842        if (msg.replyTo == null) return;
3843        Message dstMsg = obtainMessageWithArg2(msg);
3844        dstMsg.what = what;
3845        dstMsg.obj = obj;
3846        mReplyChannel.replyToMessage(msg, dstMsg);
3847    }
3848
3849    /**
3850     * arg2 on the source message has a unique id that needs to be retained in replies
3851     * to match the request
3852     *
3853     * see WifiManager for details
3854     */
3855    private Message obtainMessageWithArg2(Message srcMsg) {
3856        Message msg = Message.obtain();
3857        msg.arg2 = srcMsg.arg2;
3858        return msg;
3859    }
3860
3861    private void log(String s) {
3862        Log.d(TAG, s);
3863    }
3864
3865    private void loge(String s) {
3866        Log.e(TAG, s);
3867    }
3868}
3869