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