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