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