WifiStateMachine.java revision fcc0845cf9990470d498dcaa036f0ae6487ddf34
15f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/*
25f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project
35f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *
45f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
55f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * you may not use this file except in compliance with the License.
65f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * You may obtain a copy of the License at
75f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *
85f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
95f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *
105f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
115f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
125f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * See the License for the specific language governing permissions and
145f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * limitations under the License.
155f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */
165f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
175f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokapackage android.net.wifi;
185f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
195f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
205f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
215f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
225f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
235f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
245f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
255f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/**
265f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * TODO: Add soft AP states as part of WIFI_STATE_XXX
275f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Retain WIFI_STATE_ENABLING that indicates driver is loading
285f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
295f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * and WIFI_STATE_FAILED for failure
305f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Deprecate WIFI_STATE_UNKNOWN
315f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *
325f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Doing this will simplify the logic for sending broadcasts
335f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */
345f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
355f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
365f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
375f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
385f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
395f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
405f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.AlarmManager;
415f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.PendingIntent;
425f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.backup.IBackupManager;
435f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.bluetooth.BluetoothAdapter;
445f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.BroadcastReceiver;
455f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.Context;
465f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.Intent;
475f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.IntentFilter;
485f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.ConnectivityManager;
495f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.DhcpInfo;
505f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.DhcpInfoInternal;
515f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.InterfaceConfiguration;
525f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.LinkAddress;
535f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.LinkProperties;
545f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkInfo;
555f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkInfo.DetailedState;
565f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkUtils;
575f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.wifi.WpsResult.Status;
585f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Binder;
595f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.IBinder;
605f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.INetworkManagementService;
615f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Message;
625f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.PowerManager;
635f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Process;
645f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.RemoteException;
655f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.ServiceManager;
665f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.SystemProperties;
675f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.WorkSource;
685f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.provider.Settings;
695f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.EventLog;
705f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.Log;
715f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.LruCache;
725f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
735f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.app.IBatteryStats;
745f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.AsyncChannel;
755f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.HierarchicalState;
765f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.HierarchicalStateMachine;
775f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
785f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.net.InetAddress;
795f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.ArrayList;
805f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.List;
815f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.concurrent.atomic.AtomicInteger;
825f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.regex.Pattern;
835f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
845f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/**
855f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Track the state of Wifi connectivity. All event handling is done here,
865f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * and all changes in connectivity state are initiated here.
875f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka *
885f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * @hide
895f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */
905f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokapublic class WifiStateMachine extends HierarchicalStateMachine {
915f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
925f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private static final String TAG = "WifiStateMachine";
935f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private static final String NETWORKTYPE = "WIFI";
945f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private static final boolean DBG = false;
955f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
965f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    /* TODO: fetch a configurable interface */
975f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private static final String SOFTAP_IFACE = "wl0.1";
985f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
995f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private WifiMonitor mWifiMonitor;
1005f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private INetworkManagementService nwService;
1015f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private ConnectivityManager mCm;
1025f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka
1035f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    /* Scan results handling */
1045f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private List<ScanResult> mScanResults;
1055f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka    private static final Pattern scanResultPattern = Pattern.compile("\t+");
106    private static final int SCAN_RESULT_CACHE_SIZE = 80;
107    private final LruCache<String, ScanResult> mScanResultCache;
108
109    private String mInterfaceName;
110
111    private int mLastSignalLevel = -1;
112    private String mLastBssid;
113    private int mLastNetworkId;
114    private boolean mEnableRssiPolling = false;
115    private boolean mEnableBackgroundScan = false;
116    private int mRssiPollToken = 0;
117    private int mReconnectCount = 0;
118    private boolean mIsScanMode = false;
119    private boolean mScanResultIsPending = false;
120
121    private boolean mBluetoothConnectionActive = false;
122
123    /**
124     * Interval in milliseconds between polling for RSSI
125     * and linkspeed information
126     */
127    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
128
129    /**
130     * Delay between supplicant restarts upon failure to establish connection
131     */
132    private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
133
134    /**
135     * Number of times we attempt to restart supplicant
136     */
137    private static final int SUPPLICANT_RESTART_TRIES = 5;
138
139    private int mSupplicantRestartCount = 0;
140
141    private LinkProperties mLinkProperties;
142
143    // Wakelock held during wifi start/stop and driver load/unload
144    private PowerManager.WakeLock mWakeLock;
145
146    private Context mContext;
147
148    private DhcpInfoInternal mDhcpInfoInternal;
149    private WifiInfo mWifiInfo;
150    private NetworkInfo mNetworkInfo;
151    private SupplicantStateTracker mSupplicantStateTracker;
152    private WpsStateMachine mWpsStateMachine;
153
154    private AlarmManager mAlarmManager;
155    private PendingIntent mScanIntent;
156    /* Tracks current frequency mode */
157    private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
158
159    // Channel for sending replies.
160    private AsyncChannel mReplyChannel = new AsyncChannel();
161
162    // Event log tags (must be in sync with event-log-tags)
163    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
164    private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
165    private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
166
167    /* Load the driver */
168    static final int CMD_LOAD_DRIVER                      = 1;
169    /* Unload the driver */
170    static final int CMD_UNLOAD_DRIVER                    = 2;
171    /* Indicates driver load succeeded */
172    static final int CMD_LOAD_DRIVER_SUCCESS              = 3;
173    /* Indicates driver load failed */
174    static final int CMD_LOAD_DRIVER_FAILURE              = 4;
175    /* Indicates driver unload succeeded */
176    static final int CMD_UNLOAD_DRIVER_SUCCESS            = 5;
177    /* Indicates driver unload failed */
178    static final int CMD_UNLOAD_DRIVER_FAILURE            = 6;
179
180    /* Start the supplicant */
181    static final int CMD_START_SUPPLICANT                 = 11;
182    /* Stop the supplicant */
183    static final int CMD_STOP_SUPPLICANT                  = 12;
184    /* Start the driver */
185    static final int CMD_START_DRIVER                     = 13;
186    /* Start the driver */
187    static final int CMD_STOP_DRIVER                      = 14;
188    /* Indicates DHCP succeded */
189    static final int CMD_IP_CONFIG_SUCCESS                = 15;
190    /* Indicates DHCP failed */
191    static final int CMD_IP_CONFIG_FAILURE                = 16;
192
193    /* Start the soft access point */
194    static final int CMD_START_AP                         = 21;
195    /* Stop the soft access point */
196    static final int CMD_STOP_AP                          = 22;
197
198    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = 23;
199
200    /* Supplicant events */
201    /* Connection to supplicant established */
202    static final int SUP_CONNECTION_EVENT                 = 31;
203    /* Connection to supplicant lost */
204    static final int SUP_DISCONNECTION_EVENT              = 32;
205    /* Driver start completed */
206    static final int DRIVER_START_EVENT                   = 33;
207    /* Driver stop completed */
208    static final int DRIVER_STOP_EVENT                    = 34;
209    /* Network connection completed */
210    static final int NETWORK_CONNECTION_EVENT             = 36;
211    /* Network disconnection completed */
212    static final int NETWORK_DISCONNECTION_EVENT          = 37;
213    /* Scan results are available */
214    static final int SCAN_RESULTS_EVENT                   = 38;
215    /* Supplicate state changed */
216    static final int SUPPLICANT_STATE_CHANGE_EVENT        = 39;
217    /* Password failure and EAP authentication failure */
218    static final int AUTHENTICATION_FAILURE_EVENT         = 40;
219    /* WPS overlap detected */
220    static final int WPS_OVERLAP_EVENT                    = 41;
221
222
223    /* Supplicant commands */
224    /* Is supplicant alive ? */
225    static final int CMD_PING_SUPPLICANT                  = 51;
226    /* Add/update a network configuration */
227    static final int CMD_ADD_OR_UPDATE_NETWORK            = 52;
228    /* Delete a network */
229    static final int CMD_REMOVE_NETWORK                   = 53;
230    /* Enable a network. The device will attempt a connection to the given network. */
231    static final int CMD_ENABLE_NETWORK                   = 54;
232    /* Enable all networks */
233    static final int CMD_ENABLE_ALL_NETWORKS              = 55;
234    /* Disable a network. The device does not attempt a connection to the given network. */
235    static final int CMD_DISABLE_NETWORK                  = 56;
236    /* Blacklist network. De-prioritizes the given BSSID for connection. */
237    static final int CMD_BLACKLIST_NETWORK                = 57;
238    /* Clear the blacklist network list */
239    static final int CMD_CLEAR_BLACKLIST                  = 58;
240    /* Save configuration */
241    static final int CMD_SAVE_CONFIG                      = 59;
242
243    /* Supplicant commands after driver start*/
244    /* Initiate a scan */
245    static final int CMD_START_SCAN                       = 71;
246    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
247    static final int CMD_SET_SCAN_MODE                    = 72;
248    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
249    static final int CMD_SET_SCAN_TYPE                    = 73;
250    /* Disconnect from a network */
251    static final int CMD_DISCONNECT                       = 74;
252    /* Reconnect to a network */
253    static final int CMD_RECONNECT                        = 75;
254    /* Reassociate to a network */
255    static final int CMD_REASSOCIATE                      = 76;
256    /* Controls power mode and suspend mode optimizations
257     *
258     * When high perf mode is enabled, power mode is set to
259     * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
260     *
261     * When high perf mode is disabled, power mode is set to
262     * POWER_MODE_AUTO and suspend mode optimizations are enabled
263     *
264     * Suspend mode optimizations include:
265     * - packet filtering
266     * - turn off roaming
267     * - DTIM wake up settings
268     */
269    static final int CMD_SET_HIGH_PERF_MODE               = 77;
270    /* Set the country code */
271    static final int CMD_SET_COUNTRY_CODE                 = 80;
272    /* Request connectivity manager wake lock before driver stop */
273    static final int CMD_REQUEST_CM_WAKELOCK              = 81;
274    /* Enables RSSI poll */
275    static final int CMD_ENABLE_RSSI_POLL                 = 82;
276    /* RSSI poll */
277    static final int CMD_RSSI_POLL                        = 83;
278    /* Set up packet filtering */
279    static final int CMD_START_PACKET_FILTERING           = 84;
280    /* Clear packet filter */
281    static final int CMD_STOP_PACKET_FILTERING            = 85;
282    /* Connect to a specified network (network id
283     * or WifiConfiguration) This involves increasing
284     * the priority of the network, enabling the network
285     * (while disabling others) and issuing a reconnect.
286     * Note that CMD_RECONNECT just does a reconnect to
287     * an existing network. All the networks get enabled
288     * upon a successful connection or a failure.
289     */
290    static final int CMD_CONNECT_NETWORK                  = 86;
291    /* Save the specified network. This involves adding
292     * an enabled network (if new) and updating the
293     * config and issuing a save on supplicant config.
294     */
295    static final int CMD_SAVE_NETWORK                     = 87;
296    /* Delete the specified network. This involves
297     * removing the network and issuing a save on
298     * supplicant config.
299     */
300    static final int CMD_FORGET_NETWORK                   = 88;
301    /* Start Wi-Fi protected setup */
302    static final int CMD_START_WPS                        = 89;
303    /* Set the frequency band */
304    static final int CMD_SET_FREQUENCY_BAND               = 90;
305    /* Enable background scan for configured networks */
306    static final int CMD_ENABLE_BACKGROUND_SCAN           = 91;
307
308    /* Commands from/to the SupplicantStateTracker */
309    /* Reset the supplicant state tracker */
310    static final int CMD_RESET_SUPPLICANT_STATE           = 111;
311
312    /* Commands/events reported by WpsStateMachine */
313    /* Indicates the completion of WPS activity */
314    static final int WPS_COMPLETED_EVENT                  = 121;
315    /* Reset the WPS state machine */
316    static final int CMD_RESET_WPS_STATE                  = 122;
317
318    private static final int CONNECT_MODE   = 1;
319    private static final int SCAN_ONLY_MODE = 2;
320
321    private static final int SCAN_ACTIVE = 1;
322    private static final int SCAN_PASSIVE = 2;
323
324    private static final int SUCCESS = 1;
325    private static final int FAILURE = -1;
326
327    /**
328     * The maximum number of times we will retry a connection to an access point
329     * for which we have failed in acquiring an IP address from DHCP. A value of
330     * N means that we will make N+1 connection attempts in all.
331     * <p>
332     * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
333     * value if a Settings value is not present.
334     */
335    private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
336
337    private static final int POWER_MODE_ACTIVE = 1;
338    private static final int POWER_MODE_AUTO = 0;
339
340    /**
341     * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
342     * Settings.Secure value is not present.
343     */
344    private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */
345
346    /* Default parent state */
347    private HierarchicalState mDefaultState = new DefaultState();
348    /* Temporary initial state */
349    private HierarchicalState mInitialState = new InitialState();
350    /* Unloading the driver */
351    private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
352    /* Loading the driver */
353    private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
354    /* Driver load/unload failed */
355    private HierarchicalState mDriverFailedState = new DriverFailedState();
356    /* Driver loading */
357    private HierarchicalState mDriverLoadingState = new DriverLoadingState();
358    /* Driver loaded */
359    private HierarchicalState mDriverLoadedState = new DriverLoadedState();
360    /* Driver loaded, waiting for supplicant to start */
361    private HierarchicalState mSupplicantStartingState = new SupplicantStartingState();
362    /* Driver loaded and supplicant ready */
363    private HierarchicalState mSupplicantStartedState = new SupplicantStartedState();
364    /* Waiting for supplicant to stop and monitor to exit */
365    private HierarchicalState mSupplicantStoppingState = new SupplicantStoppingState();
366    /* Driver start issued, waiting for completed event */
367    private HierarchicalState mDriverStartingState = new DriverStartingState();
368    /* Driver started */
369    private HierarchicalState mDriverStartedState = new DriverStartedState();
370    /* Driver stopping */
371    private HierarchicalState mDriverStoppingState = new DriverStoppingState();
372    /* Driver stopped */
373    private HierarchicalState mDriverStoppedState = new DriverStoppedState();
374    /* Scan for networks, no connection will be established */
375    private HierarchicalState mScanModeState = new ScanModeState();
376    /* Connecting to an access point */
377    private HierarchicalState mConnectModeState = new ConnectModeState();
378    /* Fetching IP after network connection (assoc+auth complete) */
379    private HierarchicalState mConnectingState = new ConnectingState();
380    /* Connected with IP addr */
381    private HierarchicalState mConnectedState = new ConnectedState();
382    /* disconnect issued, waiting for network disconnect confirmation */
383    private HierarchicalState mDisconnectingState = new DisconnectingState();
384    /* Network is not connected, supplicant assoc+auth is not complete */
385    private HierarchicalState mDisconnectedState = new DisconnectedState();
386    /* Waiting for WPS to be completed*/
387    private HierarchicalState mWaitForWpsCompletionState = new WaitForWpsCompletionState();
388
389    /* Soft Ap is running */
390    private HierarchicalState mSoftApStartedState = new SoftApStartedState();
391
392
393    /**
394     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
395     *         {@link WifiManager#WIFI_STATE_DISABLING},
396     *         {@link WifiManager#WIFI_STATE_ENABLED},
397     *         {@link WifiManager#WIFI_STATE_ENABLING},
398     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
399     *
400     */
401    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
402
403    /**
404     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
405     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
406     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
407     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
408     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
409     *
410     */
411    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
412
413    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
414    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
415
416    private static final int SCAN_REQUEST = 0;
417    private static final String ACTION_START_SCAN =
418        "com.android.server.WifiManager.action.START_SCAN";
419
420    /**
421     * Keep track of whether WIFI is running.
422     */
423    private boolean mIsRunning = false;
424
425    /**
426     * Keep track of whether we last told the battery stats we had started.
427     */
428    private boolean mReportedRunning = false;
429
430    /**
431     * Most recently set source of starting WIFI.
432     */
433    private final WorkSource mRunningWifiUids = new WorkSource();
434
435    /**
436     * The last reported UIDs that were responsible for starting WIFI.
437     */
438    private final WorkSource mLastRunningWifiUids = new WorkSource();
439
440    private final IBatteryStats mBatteryStats;
441
442    public WifiStateMachine(Context context, String wlanInterface) {
443        super(TAG);
444
445        mContext = context;
446        mInterfaceName = wlanInterface;
447
448        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
449        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
450
451        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
452        nwService = INetworkManagementService.Stub.asInterface(b);
453
454        mWifiMonitor = new WifiMonitor(this);
455        mDhcpInfoInternal = new DhcpInfoInternal();
456        mWifiInfo = new WifiInfo();
457        mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
458        mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
459        mLinkProperties = new LinkProperties();
460
461        mNetworkInfo.setIsAvailable(false);
462        mLinkProperties.clear();
463        mLastBssid = null;
464        mLastNetworkId = -1;
465        mLastSignalLevel = -1;
466
467        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
468        Intent scanIntent = new Intent(ACTION_START_SCAN, null);
469        mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
470
471        mContext.registerReceiver(
472            new BroadcastReceiver() {
473                @Override
474                public void onReceive(Context context, Intent intent) {
475
476                    ArrayList<String> available = intent.getStringArrayListExtra(
477                            ConnectivityManager.EXTRA_AVAILABLE_TETHER);
478                    ArrayList<String> active = intent.getStringArrayListExtra(
479                            ConnectivityManager.EXTRA_ACTIVE_TETHER);
480                    updateTetherState(available, active);
481
482                }
483            },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
484
485        mContext.registerReceiver(
486                new BroadcastReceiver() {
487                    @Override
488                    public void onReceive(Context context, Intent intent) {
489                        startScan(false);
490                    }
491                },
492                new IntentFilter(ACTION_START_SCAN));
493
494        mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
495
496        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
497        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
498
499        addState(mDefaultState);
500            addState(mInitialState, mDefaultState);
501            addState(mDriverUnloadingState, mDefaultState);
502            addState(mDriverUnloadedState, mDefaultState);
503                addState(mDriverFailedState, mDriverUnloadedState);
504            addState(mDriverLoadingState, mDefaultState);
505            addState(mDriverLoadedState, mDefaultState);
506            addState(mSupplicantStartingState, mDefaultState);
507            addState(mSupplicantStartedState, mDefaultState);
508                addState(mDriverStartingState, mSupplicantStartedState);
509                addState(mDriverStartedState, mSupplicantStartedState);
510                    addState(mScanModeState, mDriverStartedState);
511                    addState(mConnectModeState, mDriverStartedState);
512                        addState(mConnectingState, mConnectModeState);
513                        addState(mConnectedState, mConnectModeState);
514                        addState(mDisconnectingState, mConnectModeState);
515                        addState(mDisconnectedState, mConnectModeState);
516                        addState(mWaitForWpsCompletionState, mConnectModeState);
517                addState(mDriverStoppingState, mSupplicantStartedState);
518                addState(mDriverStoppedState, mSupplicantStartedState);
519            addState(mSupplicantStoppingState, mDefaultState);
520            addState(mSoftApStartedState, mDefaultState);
521
522        setInitialState(mInitialState);
523
524        if (DBG) setDbg(true);
525
526        //start the state machine
527        start();
528    }
529
530    /*********************************************************
531     * Methods exposed for public use
532     ********************************************************/
533
534    /**
535     * TODO: doc
536     */
537    public boolean syncPingSupplicant(AsyncChannel channel) {
538        Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
539        boolean result = (resultMsg.arg1 != FAILURE);
540        resultMsg.recycle();
541        return result;
542    }
543
544    /**
545     * TODO: doc
546     */
547    public void startScan(boolean forceActive) {
548        sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
549                SCAN_ACTIVE : SCAN_PASSIVE, 0));
550    }
551
552    /**
553     * TODO: doc
554     */
555    public void setWifiEnabled(boolean enable) {
556        mLastEnableUid.set(Binder.getCallingUid());
557        if (enable) {
558            /* Argument is the state that is entered prior to load */
559            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
560            sendMessage(CMD_START_SUPPLICANT);
561        } else {
562            sendMessage(CMD_STOP_SUPPLICANT);
563            /* Argument is the state that is entered upon success */
564            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
565        }
566    }
567
568    /**
569     * TODO: doc
570     */
571    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
572        mLastApEnableUid.set(Binder.getCallingUid());
573        if (enable) {
574            /* Argument is the state that is entered prior to load */
575            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
576            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
577        } else {
578            sendMessage(CMD_STOP_AP);
579            /* Argument is the state that is entered upon success */
580            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
581        }
582    }
583
584    /**
585     * TODO: doc
586     */
587    public int syncGetWifiState() {
588        return mWifiState.get();
589    }
590
591    /**
592     * TODO: doc
593     */
594    public String syncGetWifiStateByName() {
595        switch (mWifiState.get()) {
596            case WIFI_STATE_DISABLING:
597                return "disabling";
598            case WIFI_STATE_DISABLED:
599                return "disabled";
600            case WIFI_STATE_ENABLING:
601                return "enabling";
602            case WIFI_STATE_ENABLED:
603                return "enabled";
604            case WIFI_STATE_UNKNOWN:
605                return "unknown state";
606            default:
607                return "[invalid state]";
608        }
609    }
610
611    /**
612     * TODO: doc
613     */
614    public int syncGetWifiApState() {
615        return mWifiApState.get();
616    }
617
618    /**
619     * TODO: doc
620     */
621    public String syncGetWifiApStateByName() {
622        switch (mWifiApState.get()) {
623            case WIFI_AP_STATE_DISABLING:
624                return "disabling";
625            case WIFI_AP_STATE_DISABLED:
626                return "disabled";
627            case WIFI_AP_STATE_ENABLING:
628                return "enabling";
629            case WIFI_AP_STATE_ENABLED:
630                return "enabled";
631            case WIFI_AP_STATE_FAILED:
632                return "failed";
633            default:
634                return "[invalid state]";
635        }
636    }
637
638    /**
639     * Get status information for the current connection, if any.
640     * @return a {@link WifiInfo} object containing information about the current connection
641     *
642     */
643    public WifiInfo syncRequestConnectionInfo() {
644        return mWifiInfo;
645    }
646
647    public DhcpInfo syncGetDhcpInfo() {
648        synchronized (mDhcpInfoInternal) {
649            return mDhcpInfoInternal.makeDhcpInfo();
650        }
651    }
652
653    /**
654     * TODO: doc
655     */
656    public void setDriverStart(boolean enable) {
657        if (enable) {
658            sendMessage(CMD_START_DRIVER);
659        } else {
660            sendMessage(CMD_STOP_DRIVER);
661        }
662    }
663
664    /**
665     * TODO: doc
666     */
667    public void setScanOnlyMode(boolean enable) {
668      if (enable) {
669          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
670      } else {
671          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
672      }
673    }
674
675    /**
676     * TODO: doc
677     */
678    public void setScanType(boolean active) {
679      if (active) {
680          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
681      } else {
682          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
683      }
684    }
685
686    /**
687     * TODO: doc
688     */
689    public List<ScanResult> syncGetScanResultsList() {
690        return mScanResults;
691    }
692
693    /**
694     * Disconnect from Access Point
695     */
696    public void disconnectCommand() {
697        sendMessage(CMD_DISCONNECT);
698    }
699
700    /**
701     * Initiate a reconnection to AP
702     */
703    public void reconnectCommand() {
704        sendMessage(CMD_RECONNECT);
705    }
706
707    /**
708     * Initiate a re-association to AP
709     */
710    public void reassociateCommand() {
711        sendMessage(CMD_REASSOCIATE);
712    }
713
714    /**
715     * Add a network synchronously
716     *
717     * @return network id of the new network
718     */
719    public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
720        Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
721        int result = resultMsg.arg1;
722        resultMsg.recycle();
723        return result;
724    }
725
726    public List<WifiConfiguration> syncGetConfiguredNetworks() {
727        return WifiConfigStore.getConfiguredNetworks();
728    }
729
730    /**
731     * Delete a network
732     *
733     * @param networkId id of the network to be removed
734     */
735    public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
736        Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
737        boolean result = (resultMsg.arg1 != FAILURE);
738        resultMsg.recycle();
739        return result;
740    }
741
742    /**
743     * Enable a network
744     *
745     * @param netId network id of the network
746     * @param disableOthers true, if all other networks have to be disabled
747     * @return {@code true} if the operation succeeds, {@code false} otherwise
748     */
749    public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
750        Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
751                disableOthers ? 1 : 0);
752        boolean result = (resultMsg.arg1 != FAILURE);
753        resultMsg.recycle();
754        return result;
755    }
756
757    /**
758     * Disable a network
759     *
760     * @param netId network id of the network
761     * @return {@code true} if the operation succeeds, {@code false} otherwise
762     */
763    public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
764        Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId);
765        boolean result = (resultMsg.arg1 != FAILURE);
766        resultMsg.recycle();
767        return result;
768    }
769
770    /**
771     * Blacklist a BSSID. This will avoid the AP if there are
772     * alternate APs to connect
773     *
774     * @param bssid BSSID of the network
775     */
776    public void addToBlacklist(String bssid) {
777        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
778    }
779
780    /**
781     * Clear the blacklist list
782     *
783     */
784    public void clearBlacklist() {
785        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
786    }
787
788    public void connectNetwork(int netId) {
789        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
790    }
791
792    public void connectNetwork(WifiConfiguration wifiConfig) {
793        /* arg1 is used to indicate netId, force a netId value of -1 when
794         * we are passing a configuration since the default value of
795         * 0 is a valid netId
796         */
797        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, -1, 0, wifiConfig));
798    }
799
800    public void saveNetwork(WifiConfiguration wifiConfig) {
801        sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig));
802    }
803
804    public void forgetNetwork(int netId) {
805        sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
806    }
807
808    public WpsResult startWps(AsyncChannel channel, WpsConfiguration config) {
809        WpsResult result;
810        switch (config.setup) {
811            case PIN_FROM_DEVICE:
812            case PBC:
813            case PIN_FROM_ACCESS_POINT:
814                //TODO: will go away with AsyncChannel use from settings
815                Message resultMsg = channel.sendMessageSynchronously(CMD_START_WPS, config);
816                result = (WpsResult) resultMsg.obj;
817                resultMsg.recycle();
818                break;
819            default:
820                result = new WpsResult(Status.FAILURE);
821                break;
822        }
823        return result;
824    }
825
826    public void enableRssiPolling(boolean enabled) {
827       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
828    }
829
830    public void enableBackgroundScan(boolean enabled) {
831       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
832    }
833
834    public void enableAllNetworks() {
835        sendMessage(CMD_ENABLE_ALL_NETWORKS);
836    }
837
838    /**
839     * Start packet filtering
840     */
841    public void startPacketFiltering() {
842        sendMessage(CMD_START_PACKET_FILTERING);
843    }
844
845    /**
846     * Stop packet filtering
847     */
848    public void stopPacketFiltering() {
849        sendMessage(CMD_STOP_PACKET_FILTERING);
850    }
851
852    /**
853     * Set high performance mode of operation.
854     * Enabling would set active power mode and disable suspend optimizations;
855     * disabling would set auto power mode and enable suspend optimizations
856     * @param enable true if enable, false otherwise
857     */
858    public void setHighPerfModeEnabled(boolean enable) {
859        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
860    }
861
862    /**
863     * Set the country code
864     * @param countryCode following ISO 3166 format
865     * @param persist {@code true} if the setting should be remembered.
866     */
867    public void setCountryCode(String countryCode, boolean persist) {
868        if (persist) {
869            Settings.Secure.putString(mContext.getContentResolver(),
870                    Settings.Secure.WIFI_COUNTRY_CODE,
871                    countryCode);
872        }
873        sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
874    }
875
876    /**
877     * Set the operational frequency band
878     * @param band
879     * @param persist {@code true} if the setting should be remembered.
880     */
881    public void setFrequencyBand(int band, boolean persist) {
882        if (persist) {
883            Settings.Secure.putInt(mContext.getContentResolver(),
884                    Settings.Secure.WIFI_FREQUENCY_BAND,
885                    band);
886        }
887        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
888    }
889
890    /**
891     * Returns the operational frequency band
892     */
893    public int getFrequencyBand() {
894        return mFrequencyBand.get();
895    }
896
897    /**
898     * Send a message indicating bluetooth adapter connection state changed
899     */
900    public void sendBluetoothAdapterStateChange(int state) {
901        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
902    }
903
904    /**
905     * Save configuration on supplicant
906     *
907     * @return {@code true} if the operation succeeds, {@code false} otherwise
908     *
909     * TODO: deprecate this
910     */
911    public boolean syncSaveConfig(AsyncChannel channel) {
912        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
913        boolean result = (resultMsg.arg1 != FAILURE);
914        resultMsg.recycle();
915        return result;
916    }
917
918    /**
919     * Request a wakelock with connectivity service to
920     * keep the device awake until we hand-off from wifi
921     * to an alternate network
922     */
923    public void requestCmWakeLock() {
924        sendMessage(CMD_REQUEST_CM_WAKELOCK);
925    }
926
927    public void updateBatteryWorkSource(WorkSource newSource) {
928        synchronized (mRunningWifiUids) {
929            try {
930                if (newSource != null) {
931                    mRunningWifiUids.set(newSource);
932                }
933                if (mIsRunning) {
934                    if (mReportedRunning) {
935                        // If the work source has changed since last time, need
936                        // to remove old work from battery stats.
937                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
938                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
939                                    mRunningWifiUids);
940                            mLastRunningWifiUids.set(mRunningWifiUids);
941                        }
942                    } else {
943                        // Now being started, report it.
944                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
945                        mLastRunningWifiUids.set(mRunningWifiUids);
946                        mReportedRunning = true;
947                    }
948                } else {
949                    if (mReportedRunning) {
950                        // Last reported we were running, time to stop.
951                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
952                        mLastRunningWifiUids.clear();
953                        mReportedRunning = false;
954                    }
955                }
956                mWakeLock.setWorkSource(newSource);
957            } catch (RemoteException ignore) {
958            }
959        }
960    }
961
962    @Override
963    public String toString() {
964        StringBuffer sb = new StringBuffer();
965        String LS = System.getProperty("line.separator");
966        sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
967        sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
968        sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
969        sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
970        sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
971        sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
972        sb.append("mLastBssid ").append(mLastBssid).append(LS);
973        sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
974        sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
975        sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
976        sb.append("Supplicant status").append(LS)
977                .append(WifiNative.statusCommand()).append(LS).append(LS);
978
979        sb.append(WifiConfigStore.dump());
980        return sb.toString();
981    }
982
983    /*********************************************************
984     * Internal private functions
985     ********************************************************/
986
987    private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
988
989        boolean wifiTethered = false;
990        boolean wifiAvailable = false;
991
992        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
993        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
994
995        if (mCm == null) {
996            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
997        }
998
999        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1000
1001        for (String intf : available) {
1002            for (String regex : wifiRegexs) {
1003                if (intf.matches(regex)) {
1004
1005                    InterfaceConfiguration ifcg = null;
1006                    try {
1007                        ifcg = service.getInterfaceConfig(intf);
1008                        if (ifcg != null) {
1009                            /* IP/netmask: 192.168.43.1/255.255.255.0 */
1010                            ifcg.addr = new LinkAddress(InetAddress.getByName("192.168.43.1"), 24);
1011                            ifcg.interfaceFlags = "[up]";
1012
1013                            service.setInterfaceConfig(intf, ifcg);
1014                        }
1015                    } catch (Exception e) {
1016                        Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
1017                        setWifiApEnabled(null, false);
1018                        return;
1019                    }
1020
1021                    if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1022                        Log.e(TAG, "Error tethering on " + intf);
1023                        setWifiApEnabled(null, false);
1024                        return;
1025                    }
1026                    break;
1027                }
1028            }
1029        }
1030    }
1031
1032    /**
1033     * Set the country code from the system setting value, if any.
1034     */
1035    private void setCountryCode() {
1036        String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1037                Settings.Secure.WIFI_COUNTRY_CODE);
1038        if (countryCode != null && !countryCode.isEmpty()) {
1039            setCountryCode(countryCode, false);
1040        } else {
1041            //use driver default
1042        }
1043    }
1044
1045    /**
1046     * Set the frequency band from the system setting value, if any.
1047     */
1048    private void setFrequencyBand() {
1049        int band = Settings.Secure.getInt(mContext.getContentResolver(),
1050                Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1051        setFrequencyBand(band, false);
1052    }
1053
1054    private void setWifiState(int wifiState) {
1055        final int previousWifiState = mWifiState.get();
1056
1057        try {
1058            if (wifiState == WIFI_STATE_ENABLED) {
1059                mBatteryStats.noteWifiOn();
1060            } else if (wifiState == WIFI_STATE_DISABLED) {
1061                mBatteryStats.noteWifiOff();
1062            }
1063        } catch (RemoteException e) {
1064            Log.e(TAG, "Failed to note battery stats in wifi");
1065        }
1066
1067        mWifiState.set(wifiState);
1068
1069        if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName());
1070
1071        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1072        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1073        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1074        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1075        mContext.sendStickyBroadcast(intent);
1076    }
1077
1078    private void setWifiApState(int wifiApState) {
1079        final int previousWifiApState = mWifiApState.get();
1080
1081        try {
1082            if (wifiApState == WIFI_AP_STATE_ENABLED) {
1083                mBatteryStats.noteWifiOn();
1084            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1085                mBatteryStats.noteWifiOff();
1086            }
1087        } catch (RemoteException e) {
1088            Log.d(TAG, "Failed to note battery stats in wifi");
1089        }
1090
1091        // Update state
1092        mWifiApState.set(wifiApState);
1093
1094        if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName());
1095
1096        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1097        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1098        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1099        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1100        mContext.sendStickyBroadcast(intent);
1101    }
1102
1103    /**
1104     * Parse the scan result line passed to us by wpa_supplicant (helper).
1105     * @param line the line to parse
1106     * @return the {@link ScanResult} object
1107     */
1108    private ScanResult parseScanResult(String line) {
1109        ScanResult scanResult = null;
1110        if (line != null) {
1111            /*
1112             * Cache implementation (LinkedHashMap) is not synchronized, thus,
1113             * must synchronized here!
1114             */
1115            synchronized (mScanResultCache) {
1116                String[] result = scanResultPattern.split(line);
1117                if (3 <= result.length && result.length <= 5) {
1118                    String bssid = result[0];
1119                    // bssid | frequency | level | flags | ssid
1120                    int frequency;
1121                    int level;
1122                    try {
1123                        frequency = Integer.parseInt(result[1]);
1124                        level = Integer.parseInt(result[2]);
1125                        /* some implementations avoid negative values by adding 256
1126                         * so we need to adjust for that here.
1127                         */
1128                        if (level > 0) level -= 256;
1129                    } catch (NumberFormatException e) {
1130                        frequency = 0;
1131                        level = 0;
1132                    }
1133
1134                    /*
1135                     * The formatting of the results returned by
1136                     * wpa_supplicant is intended to make the fields
1137                     * line up nicely when printed,
1138                     * not to make them easy to parse. So we have to
1139                     * apply some heuristics to figure out which field
1140                     * is the SSID and which field is the flags.
1141                     */
1142                    String ssid;
1143                    String flags;
1144                    if (result.length == 4) {
1145                        if (result[3].charAt(0) == '[') {
1146                            flags = result[3];
1147                            ssid = "";
1148                        } else {
1149                            flags = "";
1150                            ssid = result[3];
1151                        }
1152                    } else if (result.length == 5) {
1153                        flags = result[3];
1154                        ssid = result[4];
1155                    } else {
1156                        // Here, we must have 3 fields: no flags and ssid
1157                        // set
1158                        flags = "";
1159                        ssid = "";
1160                    }
1161
1162                    // bssid + ssid is the hash key
1163                    String key = bssid + ssid;
1164                    scanResult = mScanResultCache.get(key);
1165                    if (scanResult != null) {
1166                        scanResult.level = level;
1167                        scanResult.SSID = ssid;
1168                        scanResult.capabilities = flags;
1169                        scanResult.frequency = frequency;
1170                    } else {
1171                        // Do not add scan results that have no SSID set
1172                        if (0 < ssid.trim().length()) {
1173                            scanResult =
1174                                new ScanResult(
1175                                    ssid, bssid, flags, level, frequency);
1176                            mScanResultCache.put(key, scanResult);
1177                        }
1178                    }
1179                } else {
1180                    Log.w(TAG, "Misformatted scan result text with " +
1181                          result.length + " fields: " + line);
1182                }
1183            }
1184        }
1185
1186        return scanResult;
1187    }
1188
1189    /**
1190     * scanResults input format
1191     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
1192     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
1193     */
1194    private void setScanResults(String scanResults) {
1195        if (scanResults == null) {
1196            return;
1197        }
1198
1199        List<ScanResult> scanList = new ArrayList<ScanResult>();
1200
1201        int lineCount = 0;
1202
1203        int scanResultsLen = scanResults.length();
1204        // Parse the result string, keeping in mind that the last line does
1205        // not end with a newline.
1206        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
1207            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
1208                ++lineCount;
1209
1210                if (lineCount == 1) {
1211                    lineBeg = lineEnd + 1;
1212                    continue;
1213                }
1214                if (lineEnd > lineBeg) {
1215                    String line = scanResults.substring(lineBeg, lineEnd);
1216                    ScanResult scanResult = parseScanResult(line);
1217                    if (scanResult != null) {
1218                        scanList.add(scanResult);
1219                    } else {
1220                        //TODO: hidden network handling
1221                    }
1222                }
1223                lineBeg = lineEnd + 1;
1224            }
1225        }
1226
1227        mScanResults = scanList;
1228    }
1229
1230    private String fetchSSID() {
1231        String status = WifiNative.statusCommand();
1232        if (status == null) {
1233            return null;
1234        }
1235        // extract ssid from a series of "name=value"
1236        String[] lines = status.split("\n");
1237        for (String line : lines) {
1238            String[] prop = line.split(" *= *");
1239            if (prop.length < 2) continue;
1240            String name = prop[0];
1241            String value = prop[1];
1242            if (name.equalsIgnoreCase("ssid")) return value;
1243        }
1244        return null;
1245    }
1246
1247    /*
1248     * Fetch RSSI and linkspeed on current connection
1249     */
1250    private void fetchRssiAndLinkSpeedNative() {
1251        int newRssi = WifiNative.getRssiCommand();
1252        if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
1253            /* some implementations avoid negative values by adding 256
1254             * so we need to adjust for that here.
1255             */
1256            if (newRssi > 0) newRssi -= 256;
1257            mWifiInfo.setRssi(newRssi);
1258            /*
1259             * Rather then sending the raw RSSI out every time it
1260             * changes, we precalculate the signal level that would
1261             * be displayed in the status bar, and only send the
1262             * broadcast if that much more coarse-grained number
1263             * changes. This cuts down greatly on the number of
1264             * broadcasts, at the cost of not mWifiInforming others
1265             * interested in RSSI of all the changes in signal
1266             * level.
1267             */
1268            // TODO: The second arg to the call below needs to be a symbol somewhere, but
1269            // it's actually the size of an array of icons that's private
1270            // to StatusBar Policy.
1271            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
1272            if (newSignalLevel != mLastSignalLevel) {
1273                sendRssiChangeBroadcast(newRssi);
1274            }
1275            mLastSignalLevel = newSignalLevel;
1276        } else {
1277            mWifiInfo.setRssi(-200);
1278        }
1279        int newLinkSpeed = WifiNative.getLinkSpeedCommand();
1280        if (newLinkSpeed != -1) {
1281            mWifiInfo.setLinkSpeed(newLinkSpeed);
1282        }
1283    }
1284
1285    private void setHighPerfModeEnabledNative(boolean enable) {
1286        if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
1287            Log.e(TAG, "set suspend optimizations failed!");
1288        }
1289        if (enable) {
1290            if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
1291                Log.e(TAG, "set power mode active failed!");
1292            }
1293        } else {
1294            if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
1295                Log.e(TAG, "set power mode auto failed!");
1296            }
1297        }
1298    }
1299
1300    private void configureLinkProperties() {
1301        if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1302            mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
1303        } else {
1304            synchronized (mDhcpInfoInternal) {
1305                mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1306            }
1307            mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1308        }
1309        mLinkProperties.setInterfaceName(mInterfaceName);
1310        Log.d(TAG, "netId=" + mLastNetworkId  + " Link configured: " + mLinkProperties.toString());
1311    }
1312
1313    private int getMaxDhcpRetries() {
1314        return Settings.Secure.getInt(mContext.getContentResolver(),
1315                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1316                                      DEFAULT_MAX_DHCP_RETRIES);
1317    }
1318
1319    private void sendScanResultsAvailableBroadcast() {
1320        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1321        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1322        mContext.sendBroadcast(intent);
1323    }
1324
1325    private void sendRssiChangeBroadcast(final int newRssi) {
1326        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1327        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1328        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1329        mContext.sendBroadcast(intent);
1330    }
1331
1332    private void sendNetworkStateChangeBroadcast(String bssid) {
1333        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1334        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1335                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1336        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
1337        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties);
1338        if (bssid != null)
1339            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1340        mContext.sendStickyBroadcast(intent);
1341    }
1342
1343    private void sendErrorBroadcast(int errorCode) {
1344        Intent intent = new Intent(WifiManager.ERROR_ACTION);
1345        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1346        intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
1347        mContext.sendBroadcast(intent);
1348    }
1349
1350    private void sendLinkConfigurationChangedBroadcast() {
1351        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1352        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1353        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties);
1354        mContext.sendBroadcast(intent);
1355    }
1356
1357    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1358        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1359        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1360        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1361        mContext.sendBroadcast(intent);
1362    }
1363
1364    /**
1365     * Record the detailed state of a network.
1366     * @param state the new @{code DetailedState}
1367     */
1368    private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1369        Log.d(TAG, "setDetailed state, old ="
1370                + mNetworkInfo.getDetailedState() + " and new state=" + state);
1371        if (state != mNetworkInfo.getDetailedState()) {
1372            mNetworkInfo.setDetailedState(state, null, null);
1373        }
1374    }
1375
1376    private DetailedState getNetworkDetailedState() {
1377        return mNetworkInfo.getDetailedState();
1378    }
1379
1380    /**
1381     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1382     * using the interface, stopping DHCP & disabling interface
1383     */
1384    private void handleNetworkDisconnect() {
1385        Log.d(TAG, "Reset connections and stopping DHCP");
1386
1387        /*
1388         * Reset connections & stop DHCP
1389         */
1390        NetworkUtils.resetConnections(mInterfaceName);
1391
1392        if (!NetworkUtils.stopDhcp(mInterfaceName)) {
1393            Log.e(TAG, "Could not stop DHCP");
1394        }
1395
1396        /* Disable interface */
1397        NetworkUtils.disableInterface(mInterfaceName);
1398
1399        /* send event to CM & network change broadcast */
1400        setNetworkDetailedState(DetailedState.DISCONNECTED);
1401        sendNetworkStateChangeBroadcast(mLastBssid);
1402
1403        /* Reset data structures */
1404        mWifiInfo.setInetAddress(null);
1405        mWifiInfo.setBSSID(null);
1406        mWifiInfo.setSSID(null);
1407        mWifiInfo.setNetworkId(-1);
1408
1409        /* Clear network properties */
1410        mLinkProperties.clear();
1411
1412        mLastBssid= null;
1413        mLastNetworkId = -1;
1414
1415    }
1416
1417
1418    /*********************************************************
1419     * Notifications from WifiMonitor
1420     ********************************************************/
1421
1422    /**
1423     * Stores supplicant state change information passed from WifiMonitor
1424     */
1425    static class StateChangeResult {
1426        StateChangeResult(int networkId, String BSSID, SupplicantState state) {
1427            this.state = state;
1428            this.BSSID = BSSID;
1429            this.networkId = networkId;
1430        }
1431        int networkId;
1432        String BSSID;
1433        SupplicantState state;
1434    }
1435
1436    /**
1437     * Send the tracker a notification that a user provided
1438     * configuration caused authentication failure - this could
1439     * be a password failure or a EAP authentication failure
1440     */
1441    void notifyAuthenticationFailure() {
1442        sendMessage(AUTHENTICATION_FAILURE_EVENT);
1443    }
1444
1445    /**
1446     * Send a notification that the supplicant has detected overlapped
1447     * WPS sessions
1448     */
1449    void notifyWpsOverlap() {
1450        sendMessage(WPS_OVERLAP_EVENT);
1451    }
1452
1453    /**
1454     * Send the tracker a notification that a connection to the supplicant
1455     * daemon has been established.
1456     */
1457    void notifySupplicantConnection() {
1458        sendMessage(SUP_CONNECTION_EVENT);
1459    }
1460
1461    /**
1462     * Send the tracker a notification that connection to the supplicant
1463     * daemon is lost
1464     */
1465    void notifySupplicantLost() {
1466        sendMessage(SUP_DISCONNECTION_EVENT);
1467    }
1468
1469    /**
1470     * Send the tracker a notification that the state of Wifi connectivity
1471     * has changed.
1472     * @param networkId the configured network on which the state change occurred
1473     * @param newState the new network state
1474     * @param BSSID when the new state is {@link DetailedState#CONNECTED
1475     * NetworkInfo.DetailedState.CONNECTED},
1476     * this is the MAC address of the access point. Otherwise, it
1477     * is {@code null}.
1478     */
1479    void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
1480        if (newState == NetworkInfo.DetailedState.CONNECTED) {
1481            sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, networkId, 0, BSSID));
1482        } else {
1483            sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, networkId, 0, BSSID));
1484        }
1485    }
1486
1487    /**
1488     * Send the tracker a notification that the state of the supplicant
1489     * has changed.
1490     * @param networkId the configured network on which the state change occurred
1491     * @param newState the new {@code SupplicantState}
1492     */
1493    void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
1494        sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
1495                new StateChangeResult(networkId, BSSID, newState)));
1496    }
1497
1498    /**
1499     * Send the tracker a notification that a scan has completed, and results
1500     * are available.
1501     */
1502    void notifyScanResultsAvailable() {
1503        /**
1504         * Switch scan mode over to passive.
1505         * Turning off scan-only mode happens only in "Connect" mode
1506         */
1507        setScanType(false);
1508        sendMessage(SCAN_RESULTS_EVENT);
1509    }
1510
1511    void notifyDriverStarted() {
1512        sendMessage(DRIVER_START_EVENT);
1513    }
1514
1515    void notifyDriverStopped() {
1516        sendMessage(DRIVER_STOP_EVENT);
1517    }
1518
1519    void notifyDriverHung() {
1520        setWifiEnabled(false);
1521        setWifiEnabled(true);
1522    }
1523
1524    /********************************************************
1525     * HSM states
1526     *******************************************************/
1527
1528    class DefaultState extends HierarchicalState {
1529        @Override
1530        public boolean processMessage(Message message) {
1531            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1532            switch (message.what) {
1533                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1534                    mBluetoothConnectionActive = (message.arg1 !=
1535                            BluetoothAdapter.STATE_DISCONNECTED);
1536                    break;
1537                    /* Synchronous call returns */
1538                case CMD_PING_SUPPLICANT:
1539                case CMD_ENABLE_NETWORK:
1540                case CMD_DISABLE_NETWORK:
1541                case CMD_ADD_OR_UPDATE_NETWORK:
1542                case CMD_REMOVE_NETWORK:
1543                case CMD_SAVE_CONFIG:
1544                    mReplyChannel.replyToMessage(message, message.what, FAILURE);
1545                    break;
1546                case CMD_ENABLE_RSSI_POLL:
1547                    mEnableRssiPolling = (message.arg1 == 1);
1548                    break;
1549                case CMD_ENABLE_BACKGROUND_SCAN:
1550                    mEnableBackgroundScan = (message.arg1 == 1);
1551                    break;
1552                    /* Discard */
1553                case CMD_LOAD_DRIVER:
1554                case CMD_UNLOAD_DRIVER:
1555                case CMD_START_SUPPLICANT:
1556                case CMD_STOP_SUPPLICANT:
1557                case CMD_START_DRIVER:
1558                case CMD_STOP_DRIVER:
1559                case CMD_START_AP:
1560                case CMD_STOP_AP:
1561                case CMD_START_SCAN:
1562                case CMD_DISCONNECT:
1563                case CMD_RECONNECT:
1564                case CMD_REASSOCIATE:
1565                case SUP_CONNECTION_EVENT:
1566                case SUP_DISCONNECTION_EVENT:
1567                case DRIVER_START_EVENT:
1568                case DRIVER_STOP_EVENT:
1569                case NETWORK_CONNECTION_EVENT:
1570                case NETWORK_DISCONNECTION_EVENT:
1571                case SCAN_RESULTS_EVENT:
1572                case SUPPLICANT_STATE_CHANGE_EVENT:
1573                case AUTHENTICATION_FAILURE_EVENT:
1574                case WPS_OVERLAP_EVENT:
1575                case CMD_BLACKLIST_NETWORK:
1576                case CMD_CLEAR_BLACKLIST:
1577                case CMD_SET_SCAN_MODE:
1578                case CMD_SET_SCAN_TYPE:
1579                case CMD_SET_HIGH_PERF_MODE:
1580                case CMD_SET_COUNTRY_CODE:
1581                case CMD_SET_FREQUENCY_BAND:
1582                case CMD_REQUEST_CM_WAKELOCK:
1583                case CMD_CONNECT_NETWORK:
1584                case CMD_SAVE_NETWORK:
1585                case CMD_FORGET_NETWORK:
1586                case CMD_RSSI_POLL:
1587                case CMD_ENABLE_ALL_NETWORKS:
1588                    break;
1589                case CMD_START_WPS:
1590                    /* Return failure when the state machine cannot handle WPS initiation*/
1591                    mReplyChannel.replyToMessage(message, message.what,
1592                                new WpsResult(Status.FAILURE));
1593                    break;
1594                default:
1595                    Log.e(TAG, "Error! unhandled message" + message);
1596                    break;
1597            }
1598            return HANDLED;
1599        }
1600    }
1601
1602    class InitialState extends HierarchicalState {
1603        @Override
1604        //TODO: could move logging into a common class
1605        public void enter() {
1606            if (DBG) Log.d(TAG, getName() + "\n");
1607            // [31-8] Reserved for future use
1608            // [7 - 0] HSM state change
1609            // 50021 wifi_state_changed (custom|1|5)
1610            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1611
1612            if (WifiNative.isDriverLoaded()) {
1613                transitionTo(mDriverLoadedState);
1614            }
1615            else {
1616                transitionTo(mDriverUnloadedState);
1617            }
1618        }
1619    }
1620
1621    class DriverLoadingState extends HierarchicalState {
1622        @Override
1623        public void enter() {
1624            if (DBG) Log.d(TAG, getName() + "\n");
1625            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1626
1627            final Message message = new Message();
1628            message.copyFrom(getCurrentMessage());
1629            /* TODO: add a timeout to fail when driver load is hung.
1630             * Similarly for driver unload.
1631             */
1632            new Thread(new Runnable() {
1633                public void run() {
1634                    mWakeLock.acquire();
1635                    //enabling state
1636                    switch(message.arg1) {
1637                        case WIFI_STATE_ENABLING:
1638                            setWifiState(WIFI_STATE_ENABLING);
1639                            break;
1640                        case WIFI_AP_STATE_ENABLING:
1641                            setWifiApState(WIFI_AP_STATE_ENABLING);
1642                            break;
1643                    }
1644
1645                    if(WifiNative.loadDriver()) {
1646                        Log.d(TAG, "Driver load successful");
1647                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
1648                    } else {
1649                        Log.e(TAG, "Failed to load driver!");
1650                        switch(message.arg1) {
1651                            case WIFI_STATE_ENABLING:
1652                                setWifiState(WIFI_STATE_UNKNOWN);
1653                                break;
1654                            case WIFI_AP_STATE_ENABLING:
1655                                setWifiApState(WIFI_AP_STATE_FAILED);
1656                                break;
1657                        }
1658                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
1659                    }
1660                    mWakeLock.release();
1661                }
1662            }).start();
1663        }
1664
1665        @Override
1666        public boolean processMessage(Message message) {
1667            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1668            switch (message.what) {
1669                case CMD_LOAD_DRIVER_SUCCESS:
1670                    transitionTo(mDriverLoadedState);
1671                    break;
1672                case CMD_LOAD_DRIVER_FAILURE:
1673                    transitionTo(mDriverFailedState);
1674                    break;
1675                case CMD_LOAD_DRIVER:
1676                case CMD_UNLOAD_DRIVER:
1677                case CMD_START_SUPPLICANT:
1678                case CMD_STOP_SUPPLICANT:
1679                case CMD_START_AP:
1680                case CMD_STOP_AP:
1681                case CMD_START_DRIVER:
1682                case CMD_STOP_DRIVER:
1683                case CMD_SET_SCAN_MODE:
1684                case CMD_SET_SCAN_TYPE:
1685                case CMD_SET_HIGH_PERF_MODE:
1686                case CMD_SET_COUNTRY_CODE:
1687                case CMD_SET_FREQUENCY_BAND:
1688                case CMD_START_PACKET_FILTERING:
1689                case CMD_STOP_PACKET_FILTERING:
1690                    deferMessage(message);
1691                    break;
1692                default:
1693                    return NOT_HANDLED;
1694            }
1695            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1696            return HANDLED;
1697        }
1698    }
1699
1700    class DriverLoadedState extends HierarchicalState {
1701        @Override
1702        public void enter() {
1703            if (DBG) Log.d(TAG, getName() + "\n");
1704            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1705        }
1706        @Override
1707        public boolean processMessage(Message message) {
1708            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1709            switch(message.what) {
1710                case CMD_UNLOAD_DRIVER:
1711                    transitionTo(mDriverUnloadingState);
1712                    break;
1713                case CMD_START_SUPPLICANT:
1714                    if(WifiNative.startSupplicant()) {
1715                        Log.d(TAG, "Supplicant start successful");
1716                        mWifiMonitor.startMonitoring();
1717                        transitionTo(mSupplicantStartingState);
1718                    } else {
1719                        Log.e(TAG, "Failed to start supplicant!");
1720                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
1721                    }
1722                    break;
1723                case CMD_START_AP:
1724                    try {
1725                        nwService.startAccessPoint((WifiConfiguration) message.obj,
1726                                    mInterfaceName,
1727                                    SOFTAP_IFACE);
1728                    } catch (Exception e) {
1729                        Log.e(TAG, "Exception in softap start " + e);
1730                        try {
1731                            nwService.stopAccessPoint();
1732                            nwService.startAccessPoint((WifiConfiguration) message.obj,
1733                                    mInterfaceName,
1734                                    SOFTAP_IFACE);
1735                        } catch (Exception ee) {
1736                            Log.e(TAG, "Exception during softap restart : " + ee);
1737                            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
1738                            break;
1739                        }
1740                    }
1741                    Log.d(TAG, "Soft AP start successful");
1742                    setWifiApState(WIFI_AP_STATE_ENABLED);
1743                    transitionTo(mSoftApStartedState);
1744                    break;
1745                default:
1746                    return NOT_HANDLED;
1747            }
1748            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1749            return HANDLED;
1750        }
1751    }
1752
1753    class DriverUnloadingState extends HierarchicalState {
1754        @Override
1755        public void enter() {
1756            if (DBG) Log.d(TAG, getName() + "\n");
1757            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1758
1759            final Message message = new Message();
1760            message.copyFrom(getCurrentMessage());
1761            new Thread(new Runnable() {
1762                public void run() {
1763                    if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1764                    mWakeLock.acquire();
1765                    if(WifiNative.unloadDriver()) {
1766                        Log.d(TAG, "Driver unload successful");
1767                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
1768
1769                        switch(message.arg1) {
1770                            case WIFI_STATE_DISABLED:
1771                            case WIFI_STATE_UNKNOWN:
1772                                setWifiState(message.arg1);
1773                                break;
1774                            case WIFI_AP_STATE_DISABLED:
1775                            case WIFI_AP_STATE_FAILED:
1776                                setWifiApState(message.arg1);
1777                                break;
1778                        }
1779                    } else {
1780                        Log.e(TAG, "Failed to unload driver!");
1781                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
1782
1783                        switch(message.arg1) {
1784                            case WIFI_STATE_DISABLED:
1785                            case WIFI_STATE_UNKNOWN:
1786                                setWifiState(WIFI_STATE_UNKNOWN);
1787                                break;
1788                            case WIFI_AP_STATE_DISABLED:
1789                            case WIFI_AP_STATE_FAILED:
1790                                setWifiApState(WIFI_AP_STATE_FAILED);
1791                                break;
1792                        }
1793                    }
1794                    mWakeLock.release();
1795                }
1796            }).start();
1797        }
1798
1799        @Override
1800        public boolean processMessage(Message message) {
1801            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1802            switch (message.what) {
1803                case CMD_UNLOAD_DRIVER_SUCCESS:
1804                    transitionTo(mDriverUnloadedState);
1805                    break;
1806                case CMD_UNLOAD_DRIVER_FAILURE:
1807                    transitionTo(mDriverFailedState);
1808                    break;
1809                case CMD_LOAD_DRIVER:
1810                case CMD_UNLOAD_DRIVER:
1811                case CMD_START_SUPPLICANT:
1812                case CMD_STOP_SUPPLICANT:
1813                case CMD_START_AP:
1814                case CMD_STOP_AP:
1815                case CMD_START_DRIVER:
1816                case CMD_STOP_DRIVER:
1817                case CMD_SET_SCAN_MODE:
1818                case CMD_SET_SCAN_TYPE:
1819                case CMD_SET_HIGH_PERF_MODE:
1820                case CMD_SET_COUNTRY_CODE:
1821                case CMD_SET_FREQUENCY_BAND:
1822                case CMD_START_PACKET_FILTERING:
1823                case CMD_STOP_PACKET_FILTERING:
1824                    deferMessage(message);
1825                    break;
1826                default:
1827                    return NOT_HANDLED;
1828            }
1829            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1830            return HANDLED;
1831        }
1832    }
1833
1834    class DriverUnloadedState extends HierarchicalState {
1835        @Override
1836        public void enter() {
1837            if (DBG) Log.d(TAG, getName() + "\n");
1838            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1839        }
1840        @Override
1841        public boolean processMessage(Message message) {
1842            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1843            switch (message.what) {
1844                case CMD_LOAD_DRIVER:
1845                    transitionTo(mDriverLoadingState);
1846                    break;
1847                default:
1848                    return NOT_HANDLED;
1849            }
1850            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1851            return HANDLED;
1852        }
1853    }
1854
1855    class DriverFailedState extends HierarchicalState {
1856        @Override
1857        public void enter() {
1858            Log.e(TAG, getName() + "\n");
1859            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1860        }
1861        @Override
1862        public boolean processMessage(Message message) {
1863            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1864            return NOT_HANDLED;
1865        }
1866    }
1867
1868
1869    class SupplicantStartingState extends HierarchicalState {
1870        @Override
1871        public void enter() {
1872            if (DBG) Log.d(TAG, getName() + "\n");
1873            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1874        }
1875        @Override
1876        public boolean processMessage(Message message) {
1877            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1878            switch(message.what) {
1879                case SUP_CONNECTION_EVENT:
1880                    Log.d(TAG, "Supplicant connection established");
1881                    setWifiState(WIFI_STATE_ENABLED);
1882                    mSupplicantRestartCount = 0;
1883                    /* Reset the supplicant state to indicate the supplicant
1884                     * state is not known at this time */
1885                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
1886                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
1887                    /* Initialize data structures */
1888                    mLastBssid = null;
1889                    mLastNetworkId = -1;
1890                    mLastSignalLevel = -1;
1891
1892                    mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
1893
1894                    WifiConfigStore.initialize(mContext);
1895
1896                    //TODO: initialize and fix multicast filtering
1897                    //mWM.initializeMulticastFiltering();
1898
1899                    sendSupplicantConnectionChangedBroadcast(true);
1900                    transitionTo(mDriverStartedState);
1901                    break;
1902                case SUP_DISCONNECTION_EVENT:
1903                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
1904                        Log.e(TAG, "Failed to setup control channel, restart supplicant");
1905                        WifiNative.killSupplicant();
1906                        transitionTo(mDriverLoadedState);
1907                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
1908                    } else {
1909                        mSupplicantRestartCount = 0;
1910                        Log.e(TAG, "Failed " + mSupplicantRestartCount +
1911                                " times to start supplicant, unload driver");
1912                        transitionTo(mDriverLoadedState);
1913                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
1914                    }
1915                    break;
1916                case CMD_LOAD_DRIVER:
1917                case CMD_UNLOAD_DRIVER:
1918                case CMD_START_SUPPLICANT:
1919                case CMD_STOP_SUPPLICANT:
1920                case CMD_START_AP:
1921                case CMD_STOP_AP:
1922                case CMD_START_DRIVER:
1923                case CMD_STOP_DRIVER:
1924                case CMD_SET_SCAN_MODE:
1925                case CMD_SET_SCAN_TYPE:
1926                case CMD_SET_HIGH_PERF_MODE:
1927                case CMD_SET_COUNTRY_CODE:
1928                case CMD_SET_FREQUENCY_BAND:
1929                case CMD_START_PACKET_FILTERING:
1930                case CMD_STOP_PACKET_FILTERING:
1931                    deferMessage(message);
1932                    break;
1933                default:
1934                    return NOT_HANDLED;
1935            }
1936            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1937            return HANDLED;
1938        }
1939    }
1940
1941    class SupplicantStartedState extends HierarchicalState {
1942        @Override
1943        public void enter() {
1944            if (DBG) Log.d(TAG, getName() + "\n");
1945            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1946            /* Initialize for connect mode operation at start */
1947            mIsScanMode = false;
1948            /* Wifi is available as long as we have a connection to supplicant */
1949            mNetworkInfo.setIsAvailable(true);
1950        }
1951        @Override
1952        public boolean processMessage(Message message) {
1953            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1954            WifiConfiguration config;
1955            boolean eventLoggingEnabled = true;
1956            switch(message.what) {
1957                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
1958                    Log.d(TAG, "stopping supplicant");
1959                    if (!WifiNative.stopSupplicant()) {
1960                        Log.e(TAG, "Failed to stop supplicant, issue kill");
1961                        WifiNative.killSupplicant();
1962                    }
1963                    mNetworkInfo.setIsAvailable(false);
1964                    handleNetworkDisconnect();
1965                    setWifiState(WIFI_STATE_DISABLING);
1966                    sendSupplicantConnectionChangedBroadcast(false);
1967                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
1968                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
1969                    transitionTo(mSupplicantStoppingState);
1970                    break;
1971                case SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
1972                    Log.e(TAG, "Connection lost, restart supplicant");
1973                    WifiNative.killSupplicant();
1974                    WifiNative.closeSupplicantConnection();
1975                    mNetworkInfo.setIsAvailable(false);
1976                    handleNetworkDisconnect();
1977                    sendSupplicantConnectionChangedBroadcast(false);
1978                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
1979                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
1980                    transitionTo(mDriverLoadedState);
1981                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
1982                    break;
1983                case SCAN_RESULTS_EVENT:
1984                    eventLoggingEnabled = false;
1985                    setScanResults(WifiNative.scanResultsCommand());
1986                    sendScanResultsAvailableBroadcast();
1987                    mScanResultIsPending = false;
1988                    break;
1989                case CMD_PING_SUPPLICANT:
1990                    boolean ok = WifiNative.pingCommand();
1991                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
1992                    break;
1993                case CMD_ADD_OR_UPDATE_NETWORK:
1994                    config = (WifiConfiguration) message.obj;
1995                    mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
1996                            WifiConfigStore.addOrUpdateNetwork(config));
1997                    break;
1998                case CMD_REMOVE_NETWORK:
1999                    ok = WifiConfigStore.removeNetwork(message.arg1);
2000                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2001                    break;
2002                case CMD_ENABLE_NETWORK:
2003                    ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2004                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2005                    break;
2006                case CMD_ENABLE_ALL_NETWORKS:
2007                    WifiConfigStore.enableAllNetworks();
2008                    break;
2009                case CMD_DISABLE_NETWORK:
2010                    ok = WifiConfigStore.disableNetwork(message.arg1);
2011                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2012                    break;
2013                case CMD_BLACKLIST_NETWORK:
2014                    WifiNative.addToBlacklistCommand((String)message.obj);
2015                    break;
2016                case CMD_CLEAR_BLACKLIST:
2017                    WifiNative.clearBlacklistCommand();
2018                    break;
2019                case CMD_SAVE_CONFIG:
2020                    ok = WifiConfigStore.saveConfig();
2021                    mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2022
2023                    // Inform the backup manager about a data change
2024                    IBackupManager ibm = IBackupManager.Stub.asInterface(
2025                            ServiceManager.getService(Context.BACKUP_SERVICE));
2026                    if (ibm != null) {
2027                        try {
2028                            ibm.dataChanged("com.android.providers.settings");
2029                        } catch (Exception e) {
2030                            // Try again later
2031                        }
2032                    }
2033                    break;
2034                    /* Cannot start soft AP while in client mode */
2035                case CMD_START_AP:
2036                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
2037                    setWifiApState(WIFI_AP_STATE_FAILED);
2038                    break;
2039                case CMD_SET_SCAN_MODE:
2040                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2041                    break;
2042                case CMD_SAVE_NETWORK:
2043                    config = (WifiConfiguration) message.obj;
2044                    WifiConfigStore.saveNetwork(config);
2045                    break;
2046                case CMD_FORGET_NETWORK:
2047                    WifiConfigStore.forgetNetwork(message.arg1);
2048                    break;
2049                default:
2050                    return NOT_HANDLED;
2051            }
2052            if (eventLoggingEnabled) {
2053                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2054            }
2055            return HANDLED;
2056        }
2057
2058        @Override
2059        public void exit() {
2060            mNetworkInfo.setIsAvailable(false);
2061        }
2062    }
2063
2064    class SupplicantStoppingState extends HierarchicalState {
2065        @Override
2066        public void enter() {
2067            if (DBG) Log.d(TAG, getName() + "\n");
2068            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2069        }
2070        @Override
2071        public boolean processMessage(Message message) {
2072            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2073            switch(message.what) {
2074                case SUP_CONNECTION_EVENT:
2075                    Log.e(TAG, "Supplicant connection received while stopping");
2076                    break;
2077                case SUP_DISCONNECTION_EVENT:
2078                    Log.d(TAG, "Supplicant connection lost");
2079                    WifiNative.closeSupplicantConnection();
2080                    transitionTo(mDriverLoadedState);
2081                    break;
2082                case CMD_LOAD_DRIVER:
2083                case CMD_UNLOAD_DRIVER:
2084                case CMD_START_SUPPLICANT:
2085                case CMD_STOP_SUPPLICANT:
2086                case CMD_START_AP:
2087                case CMD_STOP_AP:
2088                case CMD_START_DRIVER:
2089                case CMD_STOP_DRIVER:
2090                case CMD_SET_SCAN_MODE:
2091                case CMD_SET_SCAN_TYPE:
2092                case CMD_SET_HIGH_PERF_MODE:
2093                case CMD_SET_COUNTRY_CODE:
2094                case CMD_SET_FREQUENCY_BAND:
2095                case CMD_START_PACKET_FILTERING:
2096                case CMD_STOP_PACKET_FILTERING:
2097                    deferMessage(message);
2098                    break;
2099                default:
2100                    return NOT_HANDLED;
2101            }
2102            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2103            return HANDLED;
2104        }
2105    }
2106
2107    class DriverStartingState extends HierarchicalState {
2108        @Override
2109        public void enter() {
2110            if (DBG) Log.d(TAG, getName() + "\n");
2111            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2112        }
2113        @Override
2114        public boolean processMessage(Message message) {
2115            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2116            switch(message.what) {
2117                case DRIVER_START_EVENT:
2118                    transitionTo(mDriverStartedState);
2119                    break;
2120                    /* Queue driver commands & connection events */
2121                case CMD_START_DRIVER:
2122                case CMD_STOP_DRIVER:
2123                case SUPPLICANT_STATE_CHANGE_EVENT:
2124                case NETWORK_CONNECTION_EVENT:
2125                case NETWORK_DISCONNECTION_EVENT:
2126                case AUTHENTICATION_FAILURE_EVENT:
2127                case WPS_OVERLAP_EVENT:
2128                case CMD_SET_SCAN_TYPE:
2129                case CMD_SET_HIGH_PERF_MODE:
2130                case CMD_SET_COUNTRY_CODE:
2131                case CMD_SET_FREQUENCY_BAND:
2132                case CMD_START_PACKET_FILTERING:
2133                case CMD_STOP_PACKET_FILTERING:
2134                case CMD_START_SCAN:
2135                case CMD_DISCONNECT:
2136                case CMD_REASSOCIATE:
2137                case CMD_RECONNECT:
2138                    deferMessage(message);
2139                    break;
2140                default:
2141                    return NOT_HANDLED;
2142            }
2143            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2144            return HANDLED;
2145        }
2146    }
2147
2148    class DriverStartedState extends HierarchicalState {
2149        @Override
2150        public void enter() {
2151            if (DBG) Log.d(TAG, getName() + "\n");
2152            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2153
2154            mIsRunning = true;
2155            updateBatteryWorkSource(null);
2156
2157            /**
2158             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2159             * When this mode is on, some of the low-level scan parameters used by the
2160             * driver are changed to reduce interference with bluetooth
2161             */
2162            WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2163            /* set country code */
2164            setCountryCode();
2165            /* set frequency band of operation */
2166            setFrequencyBand();
2167            /* initialize network state */
2168            setNetworkDetailedState(DetailedState.DISCONNECTED);
2169
2170            if (mIsScanMode) {
2171                WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2172                WifiNative.disconnectCommand();
2173                transitionTo(mScanModeState);
2174            } else {
2175                WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2176                WifiNative.reconnectCommand();
2177                transitionTo(mDisconnectedState);
2178            }
2179        }
2180        @Override
2181        public boolean processMessage(Message message) {
2182            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2183            boolean eventLoggingEnabled = true;
2184            switch(message.what) {
2185                case CMD_SET_SCAN_TYPE:
2186                    if (message.arg1 == SCAN_ACTIVE) {
2187                        WifiNative.setScanModeCommand(true);
2188                    } else {
2189                        WifiNative.setScanModeCommand(false);
2190                    }
2191                    break;
2192                case CMD_START_SCAN:
2193                    eventLoggingEnabled = false;
2194                    WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
2195                    mScanResultIsPending = true;
2196                    break;
2197                case CMD_SET_HIGH_PERF_MODE:
2198                    setHighPerfModeEnabledNative(message.arg1 == 1);
2199                    break;
2200                case CMD_SET_COUNTRY_CODE:
2201                    String country = (String) message.obj;
2202                    Log.d(TAG, "set country code " + country);
2203                    if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) {
2204                        Log.e(TAG, "Failed to set country code " + country);
2205                    }
2206                    break;
2207                case CMD_SET_FREQUENCY_BAND:
2208                    int band =  message.arg1;
2209                    Log.d(TAG, "set frequency band " + band);
2210                    if (WifiNative.setBandCommand(band)) {
2211                        mFrequencyBand.set(band);
2212                        //Fetch the latest scan results when frequency band is set
2213                        startScan(true);
2214                    } else {
2215                        Log.e(TAG, "Failed to set frequency band " + band);
2216                    }
2217                    break;
2218                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2219                    mBluetoothConnectionActive = (message.arg1 !=
2220                            BluetoothAdapter.STATE_DISCONNECTED);
2221                    WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2222                    break;
2223                case CMD_STOP_DRIVER:
2224                    mWakeLock.acquire();
2225                    WifiNative.stopDriverCommand();
2226                    transitionTo(mDriverStoppingState);
2227                    mWakeLock.release();
2228                    break;
2229                case CMD_START_PACKET_FILTERING:
2230                    WifiNative.startPacketFiltering();
2231                    break;
2232                case CMD_STOP_PACKET_FILTERING:
2233                    WifiNative.stopPacketFiltering();
2234                    break;
2235                default:
2236                    return NOT_HANDLED;
2237            }
2238            if (eventLoggingEnabled) {
2239                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2240            }
2241            return HANDLED;
2242        }
2243        @Override
2244        public void exit() {
2245            if (DBG) Log.d(TAG, getName() + "\n");
2246            mIsRunning = false;
2247            updateBatteryWorkSource(null);
2248            mScanResults = null;
2249        }
2250    }
2251
2252    class DriverStoppingState extends HierarchicalState {
2253        @Override
2254        public void enter() {
2255            if (DBG) Log.d(TAG, getName() + "\n");
2256            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2257        }
2258        @Override
2259        public boolean processMessage(Message message) {
2260            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2261            switch(message.what) {
2262                case DRIVER_STOP_EVENT:
2263                    transitionTo(mDriverStoppedState);
2264                    break;
2265                    /* Queue driver commands */
2266                case CMD_START_DRIVER:
2267                case CMD_STOP_DRIVER:
2268                case CMD_SET_SCAN_TYPE:
2269                case CMD_SET_HIGH_PERF_MODE:
2270                case CMD_SET_COUNTRY_CODE:
2271                case CMD_SET_FREQUENCY_BAND:
2272                case CMD_START_PACKET_FILTERING:
2273                case CMD_STOP_PACKET_FILTERING:
2274                case CMD_START_SCAN:
2275                case CMD_DISCONNECT:
2276                case CMD_REASSOCIATE:
2277                case CMD_RECONNECT:
2278                    deferMessage(message);
2279                    break;
2280                default:
2281                    return NOT_HANDLED;
2282            }
2283            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2284            return HANDLED;
2285        }
2286    }
2287
2288    class DriverStoppedState extends HierarchicalState {
2289        @Override
2290        public void enter() {
2291            if (DBG) Log.d(TAG, getName() + "\n");
2292            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2293        }
2294        @Override
2295        public boolean processMessage(Message message) {
2296            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2297            switch (message.what) {
2298                case CMD_START_DRIVER:
2299                    mWakeLock.acquire();
2300                    WifiNative.startDriverCommand();
2301                    transitionTo(mDriverStartingState);
2302                    mWakeLock.release();
2303                    break;
2304                default:
2305                    return NOT_HANDLED;
2306            }
2307            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2308            return HANDLED;
2309        }
2310    }
2311
2312    class ScanModeState extends HierarchicalState {
2313        @Override
2314        public void enter() {
2315            if (DBG) Log.d(TAG, getName() + "\n");
2316            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2317        }
2318        @Override
2319        public boolean processMessage(Message message) {
2320            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2321            switch(message.what) {
2322                case CMD_SET_SCAN_MODE:
2323                    if (message.arg1 == SCAN_ONLY_MODE) {
2324                        /* Ignore */
2325                        return HANDLED;
2326                    } else {
2327                        WifiNative.setScanResultHandlingCommand(message.arg1);
2328                        WifiNative.reconnectCommand();
2329                        mIsScanMode = false;
2330                        transitionTo(mDisconnectedState);
2331                    }
2332                    break;
2333                    /* Ignore */
2334                case CMD_DISCONNECT:
2335                case CMD_RECONNECT:
2336                case CMD_REASSOCIATE:
2337                case SUPPLICANT_STATE_CHANGE_EVENT:
2338                case NETWORK_CONNECTION_EVENT:
2339                case NETWORK_DISCONNECTION_EVENT:
2340                    break;
2341                default:
2342                    return NOT_HANDLED;
2343            }
2344            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2345            return HANDLED;
2346        }
2347    }
2348
2349    class ConnectModeState extends HierarchicalState {
2350        @Override
2351        public void enter() {
2352            if (DBG) Log.d(TAG, getName() + "\n");
2353            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2354        }
2355        @Override
2356        public boolean processMessage(Message message) {
2357            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2358            StateChangeResult stateChangeResult;
2359            switch(message.what) {
2360                case AUTHENTICATION_FAILURE_EVENT:
2361                    mSupplicantStateTracker.sendMessage(AUTHENTICATION_FAILURE_EVENT);
2362                    break;
2363                case WPS_OVERLAP_EVENT:
2364                    /* We just need to broadcast the error */
2365                    sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
2366                    break;
2367                case SUPPLICANT_STATE_CHANGE_EVENT:
2368                    stateChangeResult = (StateChangeResult) message.obj;
2369                    SupplicantState state = stateChangeResult.state;
2370                    // Supplicant state change
2371                    // [31-13] Reserved for future use
2372                    // [8 - 0] Supplicant state (as defined in SupplicantState.java)
2373                    // 50023 supplicant_state_changed (custom|1|5)
2374                    EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
2375                    mWifiInfo.setSupplicantState(state);
2376                    mWifiInfo.setNetworkId(stateChangeResult.networkId);
2377                    if (state == SupplicantState.ASSOCIATING) {
2378                        /* BSSID is valid only in ASSOCIATING state */
2379                        mWifiInfo.setBSSID(stateChangeResult.BSSID);
2380                    }
2381
2382                    mSupplicantStateTracker.sendMessage(Message.obtain(message));
2383                    mWpsStateMachine.sendMessage(Message.obtain(message));
2384                    break;
2385                    /* Do a redundant disconnect without transition */
2386                case CMD_DISCONNECT:
2387                    WifiNative.disconnectCommand();
2388                    break;
2389                case CMD_RECONNECT:
2390                    WifiNative.reconnectCommand();
2391                    break;
2392                case CMD_REASSOCIATE:
2393                    WifiNative.reassociateCommand();
2394                    break;
2395                case CMD_CONNECT_NETWORK:
2396                    int netId = message.arg1;
2397                    WifiConfiguration config = (WifiConfiguration) message.obj;
2398
2399                    /* We connect to a specific network by issuing a select
2400                     * to the WifiConfigStore. This enables the network,
2401                     * while disabling all other networks in the supplicant.
2402                     * Disabling a connected network will cause a disconnection
2403                     * from the network. A reconnectCommand() will then initiate
2404                     * a connection to the enabled network.
2405                     */
2406                    if (config != null) {
2407                        WifiConfigStore.selectNetwork(config);
2408                    } else {
2409                        WifiConfigStore.selectNetwork(netId);
2410                    }
2411
2412                    /* The state tracker handles enabling networks upon completion/failure */
2413                    mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
2414
2415                    WifiNative.reconnectCommand();
2416
2417                    /* Expect a disconnection from the old connection */
2418                    transitionTo(mDisconnectingState);
2419                    break;
2420                case CMD_START_WPS:
2421                    mWpsStateMachine.sendMessage(Message.obtain(message));
2422                    transitionTo(mWaitForWpsCompletionState);
2423                    break;
2424                case SCAN_RESULTS_EVENT:
2425                    /* Set the scan setting back to "connect" mode */
2426                    WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2427                    /* Handle scan results */
2428                    return NOT_HANDLED;
2429                case NETWORK_CONNECTION_EVENT:
2430                    Log.d(TAG,"Network connection established");
2431                    mLastNetworkId = message.arg1;
2432                    mLastBssid = (String) message.obj;
2433
2434                    //TODO: make supplicant modification to push this in events
2435                    mWifiInfo.setSSID(fetchSSID());
2436                    mWifiInfo.setBSSID(mLastBssid);
2437                    mWifiInfo.setNetworkId(mLastNetworkId);
2438                    /* send event to CM & network change broadcast */
2439                    setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
2440                    sendNetworkStateChangeBroadcast(mLastBssid);
2441                    transitionTo(mConnectingState);
2442                    break;
2443                case NETWORK_DISCONNECTION_EVENT:
2444                    Log.d(TAG,"Network connection lost");
2445                    handleNetworkDisconnect();
2446                    transitionTo(mDisconnectedState);
2447                    break;
2448                default:
2449                    return NOT_HANDLED;
2450            }
2451            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2452            return HANDLED;
2453        }
2454    }
2455
2456    class ConnectingState extends HierarchicalState {
2457        boolean mModifiedBluetoothCoexistenceMode;
2458        int mPowerMode;
2459        boolean mUseStaticIp;
2460        Thread mDhcpThread;
2461
2462        @Override
2463        public void enter() {
2464            if (DBG) Log.d(TAG, getName() + "\n");
2465            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2466            mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
2467            if (!mUseStaticIp) {
2468                mDhcpThread = null;
2469                mModifiedBluetoothCoexistenceMode = false;
2470                mPowerMode = POWER_MODE_AUTO;
2471
2472                if (!mBluetoothConnectionActive) {
2473                    /*
2474                     * There are problems setting the Wi-Fi driver's power
2475                     * mode to active when bluetooth coexistence mode is
2476                     * enabled or sense.
2477                     * <p>
2478                     * We set Wi-Fi to active mode when
2479                     * obtaining an IP address because we've found
2480                     * compatibility issues with some routers with low power
2481                     * mode.
2482                     * <p>
2483                     * In order for this active power mode to properly be set,
2484                     * we disable coexistence mode until we're done with
2485                     * obtaining an IP address.  One exception is if we
2486                     * are currently connected to a headset, since disabling
2487                     * coexistence would interrupt that connection.
2488                     */
2489                    mModifiedBluetoothCoexistenceMode = true;
2490
2491                    // Disable the coexistence mode
2492                    WifiNative.setBluetoothCoexistenceModeCommand(
2493                            WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
2494                }
2495
2496                mPowerMode =  WifiNative.getPowerModeCommand();
2497                if (mPowerMode < 0) {
2498                  // Handle the case where supplicant driver does not support
2499                  // getPowerModeCommand.
2500                    mPowerMode = POWER_MODE_AUTO;
2501                }
2502                if (mPowerMode != POWER_MODE_ACTIVE) {
2503                    WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
2504                }
2505
2506                Log.d(TAG, "DHCP request started");
2507                mDhcpThread = new Thread(new Runnable() {
2508                    public void run() {
2509                        DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
2510                        if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
2511                            Log.d(TAG, "DHCP request succeeded");
2512                            synchronized (mDhcpInfoInternal) {
2513                                mDhcpInfoInternal = dhcpInfoInternal;
2514                            }
2515                            sendMessage(CMD_IP_CONFIG_SUCCESS);
2516                        } else {
2517                            Log.d(TAG, "DHCP request failed: " +
2518                                    NetworkUtils.getDhcpError());
2519                            sendMessage(CMD_IP_CONFIG_FAILURE);
2520                        }
2521                    }
2522                });
2523                mDhcpThread.start();
2524            } else {
2525                DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
2526                        mLastNetworkId);
2527                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
2528                INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b);
2529                InterfaceConfiguration ifcg = new InterfaceConfiguration();
2530                ifcg.addr = dhcpInfoInternal.makeLinkAddress();
2531                ifcg.interfaceFlags = "[up]";
2532                try {
2533                    netd.setInterfaceConfig(mInterfaceName, ifcg);
2534                    Log.v(TAG, "Static IP configuration succeeded");
2535                    synchronized (mDhcpInfoInternal) {
2536                        mDhcpInfoInternal = dhcpInfoInternal;
2537                    }
2538                    sendMessage(CMD_IP_CONFIG_SUCCESS);
2539                } catch (RemoteException re) {
2540                    Log.v(TAG, "Static IP configuration failed: " + re);
2541                    sendMessage(CMD_IP_CONFIG_FAILURE);
2542                } catch (IllegalStateException e) {
2543                    Log.v(TAG, "Static IP configuration failed: " + e);
2544                    sendMessage(CMD_IP_CONFIG_FAILURE);
2545                }
2546            }
2547         }
2548      @Override
2549      public boolean processMessage(Message message) {
2550          if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2551
2552          switch(message.what) {
2553              case CMD_IP_CONFIG_SUCCESS:
2554                  mLastSignalLevel = -1; // force update of signal strength
2555                  InetAddress addr;
2556                  synchronized (mDhcpInfoInternal) {
2557                      addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
2558                  }
2559                  mWifiInfo.setInetAddress(addr);
2560                  configureLinkProperties();
2561                  if (getNetworkDetailedState() == DetailedState.CONNECTED) {
2562                      sendLinkConfigurationChangedBroadcast();
2563                  } else {
2564                      setNetworkDetailedState(DetailedState.CONNECTED);
2565                      sendNetworkStateChangeBroadcast(mLastBssid);
2566                  }
2567                  //TODO: The framework is not detecting a DHCP renewal and a possible
2568                  //IP change. we should detect this and send out a config change broadcast
2569                  transitionTo(mConnectedState);
2570                  break;
2571              case CMD_IP_CONFIG_FAILURE:
2572                  mWifiInfo.setInetAddress(null);
2573
2574                  Log.e(TAG, "IP configuration failed");
2575                  /**
2576                   * If we've exceeded the maximum number of retries for DHCP
2577                   * to a given network, disable the network
2578                   */
2579                  if (++mReconnectCount > getMaxDhcpRetries()) {
2580                      Log.e(TAG, "Failed " +
2581                              mReconnectCount + " times, Disabling " + mLastNetworkId);
2582                      WifiConfigStore.disableNetwork(mLastNetworkId);
2583                      mReconnectCount = 0;
2584                  }
2585
2586                  /* DHCP times out after about 30 seconds, we do a
2587                   * disconnect and an immediate reconnect to try again
2588                   */
2589                  WifiNative.disconnectCommand();
2590                  WifiNative.reconnectCommand();
2591                  transitionTo(mDisconnectingState);
2592                  break;
2593              case CMD_DISCONNECT:
2594                  WifiNative.disconnectCommand();
2595                  transitionTo(mDisconnectingState);
2596                  break;
2597                  /* Ignore connection to same network */
2598              case CMD_CONNECT_NETWORK:
2599                  int netId = message.arg1;
2600                  if (mWifiInfo.getNetworkId() == netId) {
2601                      break;
2602                  }
2603                  return NOT_HANDLED;
2604              case CMD_SAVE_NETWORK:
2605                  deferMessage(message);
2606                  break;
2607                  /* Ignore */
2608              case NETWORK_CONNECTION_EVENT:
2609                  break;
2610              case CMD_STOP_DRIVER:
2611                  sendMessage(CMD_DISCONNECT);
2612                  deferMessage(message);
2613                  break;
2614              case CMD_SET_SCAN_MODE:
2615                  if (message.arg1 == SCAN_ONLY_MODE) {
2616                      sendMessage(CMD_DISCONNECT);
2617                      deferMessage(message);
2618                  }
2619                  break;
2620                  /* Defer scan when IP is being fetched */
2621              case CMD_START_SCAN:
2622                  deferMessage(message);
2623                  break;
2624                  /* Defer any power mode changes since we must keep active power mode at DHCP */
2625              case CMD_SET_HIGH_PERF_MODE:
2626                  deferMessage(message);
2627                  break;
2628              default:
2629                return NOT_HANDLED;
2630          }
2631          EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2632          return HANDLED;
2633      }
2634
2635      @Override
2636      public void exit() {
2637          /* reset power state & bluetooth coexistence if on DHCP */
2638          if (!mUseStaticIp) {
2639              if (mPowerMode != POWER_MODE_ACTIVE) {
2640                  WifiNative.setPowerModeCommand(mPowerMode);
2641              }
2642
2643              if (mModifiedBluetoothCoexistenceMode) {
2644                  // Set the coexistence mode back to its default value
2645                  WifiNative.setBluetoothCoexistenceModeCommand(
2646                          WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
2647              }
2648          }
2649
2650      }
2651    }
2652
2653    class ConnectedState extends HierarchicalState {
2654        @Override
2655        public void enter() {
2656            if (DBG) Log.d(TAG, getName() + "\n");
2657            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2658            mRssiPollToken++;
2659            if (mEnableRssiPolling) {
2660                sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0));
2661            }
2662        }
2663        @Override
2664        public boolean processMessage(Message message) {
2665            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2666            boolean eventLoggingEnabled = true;
2667            switch (message.what) {
2668                case CMD_DISCONNECT:
2669                    WifiNative.disconnectCommand();
2670                    transitionTo(mDisconnectingState);
2671                    break;
2672                case CMD_STOP_DRIVER:
2673                    sendMessage(CMD_DISCONNECT);
2674                    deferMessage(message);
2675                    break;
2676                case CMD_REQUEST_CM_WAKELOCK:
2677                    if (mCm == null) {
2678                        mCm = (ConnectivityManager)mContext.getSystemService(
2679                                Context.CONNECTIVITY_SERVICE);
2680                    }
2681                    mCm.requestNetworkTransitionWakelock(TAG);
2682                    break;
2683                case CMD_SET_SCAN_MODE:
2684                    if (message.arg1 == SCAN_ONLY_MODE) {
2685                        sendMessage(CMD_DISCONNECT);
2686                        deferMessage(message);
2687                    }
2688                    break;
2689                case CMD_START_SCAN:
2690                    eventLoggingEnabled = false;
2691                    /* When the network is connected, re-scanning can trigger
2692                     * a reconnection. Put it in scan-only mode during scan.
2693                     * When scan results are received, the mode is switched
2694                     * back to CONNECT_MODE.
2695                     */
2696                    WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2697                    /* Have the parent state handle the rest */
2698                    return NOT_HANDLED;
2699                    /* Ignore connection to same network */
2700                case CMD_CONNECT_NETWORK:
2701                    int netId = message.arg1;
2702                    if (mWifiInfo.getNetworkId() == netId) {
2703                        break;
2704                    }
2705                    return NOT_HANDLED;
2706                case CMD_SAVE_NETWORK:
2707                    WifiConfiguration config = (WifiConfiguration) message.obj;
2708                    NetworkUpdateResult result = WifiConfigStore.saveNetwork(config);
2709                    if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
2710                        if (result.hasIpChanged()) {
2711                            Log.d(TAG,"Reconfiguring IP on connection");
2712                            NetworkUtils.resetConnections(mInterfaceName);
2713                            transitionTo(mConnectingState);
2714                        }
2715                        if (result.hasProxyChanged()) {
2716                            Log.d(TAG,"Reconfiguring proxy on connection");
2717                            configureLinkProperties();
2718                            sendLinkConfigurationChangedBroadcast();
2719                        }
2720                    }
2721                    break;
2722                    /* Ignore */
2723                case NETWORK_CONNECTION_EVENT:
2724                    break;
2725                case CMD_RSSI_POLL:
2726                    eventLoggingEnabled = false;
2727                    if (message.arg1 == mRssiPollToken) {
2728                        // Get Info and continue polling
2729                        fetchRssiAndLinkSpeedNative();
2730                        sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2731                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2732                    } else {
2733                        // Polling has completed
2734                    }
2735                    break;
2736                case CMD_ENABLE_RSSI_POLL:
2737                    mEnableRssiPolling = (message.arg1 == 1);
2738                    mRssiPollToken++;
2739                    if (mEnableRssiPolling) {
2740                        // first poll
2741                        fetchRssiAndLinkSpeedNative();
2742                        sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2743                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2744                    }
2745                    break;
2746                default:
2747                    return NOT_HANDLED;
2748            }
2749            if (eventLoggingEnabled) {
2750                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2751            }
2752            return HANDLED;
2753        }
2754    }
2755
2756    class DisconnectingState extends HierarchicalState {
2757        @Override
2758        public void enter() {
2759            if (DBG) Log.d(TAG, getName() + "\n");
2760            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2761        }
2762        @Override
2763        public boolean processMessage(Message message) {
2764            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2765            switch (message.what) {
2766                case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
2767                    deferMessage(message);
2768                    break;
2769                case CMD_SET_SCAN_MODE:
2770                    if (message.arg1 == SCAN_ONLY_MODE) {
2771                        deferMessage(message);
2772                    }
2773                    break;
2774                    /* Handle in  DisconnectedState */
2775                case SUPPLICANT_STATE_CHANGE_EVENT:
2776                    deferMessage(message);
2777                    break;
2778                default:
2779                    return NOT_HANDLED;
2780            }
2781            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2782            return HANDLED;
2783        }
2784    }
2785
2786    class DisconnectedState extends HierarchicalState {
2787        private boolean mAlarmEnabled = false;
2788        @Override
2789        public void enter() {
2790            if (DBG) Log.d(TAG, getName() + "\n");
2791            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2792
2793            /*
2794             * We initiate background scanning if it is enabled, otherwise we
2795             * initiate an infrequent scan that wakes up the device to ensure
2796             * a user connects to an access point on the move
2797             */
2798            if (mEnableBackgroundScan) {
2799                /* If a regular scan result is pending, do not initiate background
2800                 * scan until the scan results are returned. This is needed because
2801                 * initiating a background scan will cancel the regular scan and
2802                 * scan results will not be returned until background scanning is
2803                 * cleared
2804                 */
2805                if (!mScanResultIsPending) {
2806                    WifiNative.enableBackgroundScan(true);
2807                }
2808            } else {
2809                long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
2810                    Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
2811
2812                mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
2813                    System.currentTimeMillis() + scanMs, scanMs, mScanIntent);
2814                mAlarmEnabled = true;
2815            }
2816        }
2817        @Override
2818        public boolean processMessage(Message message) {
2819            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2820            switch (message.what) {
2821                case CMD_SET_SCAN_MODE:
2822                    if (message.arg1 == SCAN_ONLY_MODE) {
2823                        WifiNative.setScanResultHandlingCommand(message.arg1);
2824                        //Supplicant disconnect to prevent further connects
2825                        WifiNative.disconnectCommand();
2826                        mIsScanMode = true;
2827                        transitionTo(mScanModeState);
2828                    }
2829                    break;
2830                case CMD_ENABLE_BACKGROUND_SCAN:
2831                    mEnableBackgroundScan = (message.arg1 == 1);
2832                    WifiNative.enableBackgroundScan(mEnableBackgroundScan);
2833                    break;
2834                    /* Ignore network disconnect */
2835                case NETWORK_DISCONNECTION_EVENT:
2836                    break;
2837                case SUPPLICANT_STATE_CHANGE_EVENT:
2838                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2839                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
2840                    /* DriverStartedState does the rest of the handling */
2841                    return NOT_HANDLED;
2842                case CMD_START_SCAN:
2843                    /* Disable background scan temporarily during a regular scan */
2844                    if (mEnableBackgroundScan) {
2845                        WifiNative.enableBackgroundScan(false);
2846                    }
2847                    /* Handled in parent state */
2848                    return NOT_HANDLED;
2849                case SCAN_RESULTS_EVENT:
2850                    /* Re-enable background scan when a pending scan result is received */
2851                    if (mEnableBackgroundScan && mScanResultIsPending) {
2852                        WifiNative.enableBackgroundScan(true);
2853                    }
2854                    /* Handled in parent state */
2855                    return NOT_HANDLED;
2856                default:
2857                    return NOT_HANDLED;
2858            }
2859            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2860            return HANDLED;
2861        }
2862
2863        @Override
2864        public void exit() {
2865            /* No need for a background scan upon exit from a disconnected state */
2866            if (mEnableBackgroundScan) {
2867                WifiNative.enableBackgroundScan(false);
2868            }
2869            if (mAlarmEnabled) {
2870                mAlarmManager.cancel(mScanIntent);
2871                mAlarmEnabled = false;
2872            }
2873        }
2874    }
2875
2876    class WaitForWpsCompletionState extends HierarchicalState {
2877        @Override
2878        public void enter() {
2879            if (DBG) Log.d(TAG, getName() + "\n");
2880            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2881        }
2882        @Override
2883        public boolean processMessage(Message message) {
2884            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2885            switch (message.what) {
2886                /* Defer all commands that can cause connections to a different network
2887                 * or put the state machine out of connect mode
2888                 */
2889                case CMD_STOP_DRIVER:
2890                case CMD_SET_SCAN_MODE:
2891                case CMD_CONNECT_NETWORK:
2892                case CMD_ENABLE_NETWORK:
2893                case CMD_RECONNECT:
2894                case CMD_REASSOCIATE:
2895                case NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */
2896                    deferMessage(message);
2897                    break;
2898                case NETWORK_DISCONNECTION_EVENT:
2899                    Log.d(TAG,"Network connection lost");
2900                    handleNetworkDisconnect();
2901                    break;
2902                case WPS_COMPLETED_EVENT:
2903                    /* we are still disconnected until we see a network connection
2904                     * notification */
2905                    transitionTo(mDisconnectedState);
2906                    break;
2907                default:
2908                    return NOT_HANDLED;
2909            }
2910            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2911            return HANDLED;
2912        }
2913    }
2914
2915    class SoftApStartedState extends HierarchicalState {
2916        @Override
2917        public void enter() {
2918            if (DBG) Log.d(TAG, getName() + "\n");
2919            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2920        }
2921        @Override
2922        public boolean processMessage(Message message) {
2923            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2924            switch(message.what) {
2925                case CMD_STOP_AP:
2926                    Log.d(TAG,"Stopping Soft AP");
2927                    setWifiApState(WIFI_AP_STATE_DISABLING);
2928
2929                    if (mCm == null) {
2930                        mCm = (ConnectivityManager) mContext.getSystemService(
2931                                Context.CONNECTIVITY_SERVICE);
2932                    }
2933                    if (mCm.untether(SOFTAP_IFACE) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
2934                        Log.e(TAG, "Untether initiate failed!");
2935                    }
2936                    try {
2937                        nwService.stopAccessPoint();
2938                    } catch(Exception e) {
2939                        Log.e(TAG, "Exception in stopAccessPoint()");
2940                    }
2941                    transitionTo(mDriverLoadedState);
2942                    break;
2943                case CMD_START_AP:
2944                    Log.d(TAG,"SoftAP set on a running access point");
2945                    try {
2946                        nwService.setAccessPoint((WifiConfiguration) message.obj,
2947                                    mInterfaceName,
2948                                    SOFTAP_IFACE);
2949                    } catch(Exception e) {
2950                        Log.e(TAG, "Exception in softap set " + e);
2951                        try {
2952                            nwService.stopAccessPoint();
2953                            nwService.startAccessPoint((WifiConfiguration) message.obj,
2954                                    mInterfaceName,
2955                                    SOFTAP_IFACE);
2956                        } catch (Exception ee) {
2957                            Log.e(TAG, "Could not restart softap after set failed " + ee);
2958                            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
2959                        }
2960                    }
2961                    break;
2962                /* Fail client mode operation when soft AP is enabled */
2963                case CMD_START_SUPPLICANT:
2964                    Log.e(TAG,"Cannot start supplicant with a running soft AP");
2965                    setWifiState(WIFI_STATE_UNKNOWN);
2966                    break;
2967                default:
2968                    return NOT_HANDLED;
2969            }
2970            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2971            return HANDLED;
2972        }
2973    }
2974}
2975