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