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