2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.net.wifi;
19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
26 * TODO: Add soft AP states as part of WIFI_STATE_XXX
27 * Retain WIFI_STATE_ENABLING that indicates driver is loading
28 * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
29 * and WIFI_STATE_FAILED for failure
30 * Deprecate WIFI_STATE_UNKNOWN
32 * Doing this will simplify the logic for sending broadcasts
34 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
35 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
36 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
37 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
38 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
40 import android.app.AlarmManager;
41 import android.app.PendingIntent;
42 import android.app.backup.IBackupManager;
43 import android.bluetooth.BluetoothAdapter;
44 import android.content.BroadcastReceiver;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.IntentFilter;
48 import android.net.ConnectivityManager;
49 import android.net.DhcpInfo;
50 import android.net.DhcpInfoInternal;
51 import android.net.DhcpStateMachine;
52 import android.net.InterfaceConfiguration;
53 import android.net.LinkAddress;
54 import android.net.LinkProperties;
55 import android.net.NetworkInfo;
56 import android.net.NetworkInfo.DetailedState;
57 import android.net.NetworkUtils;
58 import android.net.wifi.WpsResult.Status;
59 import android.os.Binder;
60 import android.os.IBinder;
61 import android.os.INetworkManagementService;
62 import android.os.Message;
63 import android.os.Messenger;
64 import android.os.PowerManager;
65 import android.os.Process;
66 import android.os.RemoteException;
67 import android.os.ServiceManager;
68 import android.os.SystemProperties;
69 import android.os.WorkSource;
70 import android.provider.Settings;
71 import android.util.EventLog;
72 import android.util.Log;
73 import android.util.LruCache;
75 import com.android.internal.app.IBatteryStats;
76 import com.android.internal.util.AsyncChannel;
77 import com.android.internal.util.Protocol;
78 import com.android.internal.util.State;
79 import com.android.internal.util.StateMachine;
81 import java.net.InetAddress;
82 import java.util.ArrayList;
83 import java.util.List;
84 import java.util.concurrent.atomic.AtomicInteger;
85 import java.util.regex.Pattern;
88 * Track the state of Wifi connectivity. All event handling is done here,
89 * and all changes in connectivity state are initiated here.
93 public class WifiStateMachine extends StateMachine {
95 private static final String TAG = "WifiStateMachine";
96 private static final String NETWORKTYPE = "WIFI";
97 private static final boolean DBG = false;
99 /* TODO: fetch a configurable interface */
100 private static final String SOFTAP_IFACE = "wl0.1";
102 private WifiMonitor mWifiMonitor;
103 private INetworkManagementService nwService;
104 private ConnectivityManager mCm;
106 /* Scan results handling */
107 private List<ScanResult> mScanResults;
108 private static final Pattern scanResultPattern = Pattern.compile("\t+");
109 private static final int SCAN_RESULT_CACHE_SIZE = 80;
110 private final LruCache<String, ScanResult> mScanResultCache;
112 private String mInterfaceName;
114 private int mLastSignalLevel = -1;
115 private String mLastBssid;
116 private int mLastNetworkId;
117 private boolean mEnableRssiPolling = false;
118 private boolean mEnableBackgroundScan = false;
119 private int mRssiPollToken = 0;
120 private int mReconnectCount = 0;
121 private boolean mIsScanMode = false;
122 private boolean mScanResultIsPending = false;
124 private boolean mBluetoothConnectionActive = false;
127 * Interval in milliseconds between polling for RSSI
128 * and linkspeed information
130 private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
133 * Delay between supplicant restarts upon failure to establish connection
135 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
138 * Number of times we attempt to restart supplicant
140 private static final int SUPPLICANT_RESTART_TRIES = 5;
142 private int mSupplicantRestartCount = 0;
144 private LinkProperties mLinkProperties;
146 // Wakelock held during wifi start/stop and driver load/unload
147 private PowerManager.WakeLock mWakeLock;
149 private Context mContext;
151 private DhcpInfoInternal mDhcpInfoInternal;
152 private WifiInfo mWifiInfo;
153 private NetworkInfo mNetworkInfo;
154 private SupplicantStateTracker mSupplicantStateTracker;
155 private WpsStateMachine mWpsStateMachine;
156 private DhcpStateMachine mDhcpStateMachine;
158 private AlarmManager mAlarmManager;
159 private PendingIntent mScanIntent;
160 /* Tracks current frequency mode */
161 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
163 // Channel for sending replies.
164 private AsyncChannel mReplyChannel = new AsyncChannel();
166 // Event log tags (must be in sync with event-log-tags)
167 private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021;
168 private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022;
169 private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023;
171 /* The base for wifi message types */
172 static final int BASE = Protocol.BASE_WIFI;
173 /* Load the driver */
174 static final int CMD_LOAD_DRIVER = BASE + 1;
175 /* Unload the driver */
176 static final int CMD_UNLOAD_DRIVER = BASE + 2;
177 /* Indicates driver load succeeded */
178 static final int CMD_LOAD_DRIVER_SUCCESS = BASE + 3;
179 /* Indicates driver load failed */
180 static final int CMD_LOAD_DRIVER_FAILURE = BASE + 4;
181 /* Indicates driver unload succeeded */
182 static final int CMD_UNLOAD_DRIVER_SUCCESS = BASE + 5;
183 /* Indicates driver unload failed */
184 static final int CMD_UNLOAD_DRIVER_FAILURE = BASE + 6;
186 /* Start the supplicant */
187 static final int CMD_START_SUPPLICANT = BASE + 11;
188 /* Stop the supplicant */
189 static final int CMD_STOP_SUPPLICANT = BASE + 12;
190 /* Start the driver */
191 static final int CMD_START_DRIVER = BASE + 13;
192 /* Start the driver */
193 static final int CMD_STOP_DRIVER = BASE + 14;
194 /* Indicates Static IP succeded */
195 static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
196 /* Indicates Static IP failed */
197 static final int CMD_STATIC_IP_FAILURE = BASE + 16;
199 /* Start the soft access point */
200 static final int CMD_START_AP = BASE + 21;
201 /* Stop the soft access point */
202 static final int CMD_STOP_AP = BASE + 22;
203 /* Set the soft access point configuration */
204 static final int CMD_SET_AP_CONFIG = BASE + 23;
205 /* Get the soft access point configuration */
206 static final int CMD_GET_AP_CONFIG = BASE + 24;
208 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 25;
210 /* Supplicant events */
211 /* Connection to supplicant established */
212 static final int SUP_CONNECTION_EVENT = BASE + 31;
213 /* Connection to supplicant lost */
214 static final int SUP_DISCONNECTION_EVENT = BASE + 32;
215 /* Driver start completed */
216 static final int DRIVER_START_EVENT = BASE + 33;
217 /* Driver stop completed */
218 static final int DRIVER_STOP_EVENT = BASE + 34;
219 /* Network connection completed */
220 static final int NETWORK_CONNECTION_EVENT = BASE + 36;
221 /* Network disconnection completed */
222 static final int NETWORK_DISCONNECTION_EVENT = BASE + 37;
223 /* Scan results are available */
224 static final int SCAN_RESULTS_EVENT = BASE + 38;
225 /* Supplicate state changed */
226 static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 39;
227 /* Password failure and EAP authentication failure */
228 static final int AUTHENTICATION_FAILURE_EVENT = BASE + 40;
229 /* WPS overlap detected */
230 static final int WPS_OVERLAP_EVENT = BASE + 41;
233 /* Supplicant commands */
234 /* Is supplicant alive ? */
235 static final int CMD_PING_SUPPLICANT = BASE + 51;
236 /* Add/update a network configuration */
237 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52;
238 /* Delete a network */
239 static final int CMD_REMOVE_NETWORK = BASE + 53;
240 /* Enable a network. The device will attempt a connection to the given network. */
241 static final int CMD_ENABLE_NETWORK = BASE + 54;
242 /* Enable all networks */
243 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55;
244 /* Disable a network. The device does not attempt a connection to the given network. */
245 static final int CMD_DISABLE_NETWORK = BASE + 56;
246 /* Blacklist network. De-prioritizes the given BSSID for connection. */
247 static final int CMD_BLACKLIST_NETWORK = BASE + 57;
248 /* Clear the blacklist network list */
249 static final int CMD_CLEAR_BLACKLIST = BASE + 58;
250 /* Save configuration */
251 static final int CMD_SAVE_CONFIG = BASE + 59;
253 /* Supplicant commands after driver start*/
254 /* Initiate a scan */
255 static final int CMD_START_SCAN = BASE + 71;
256 /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
257 static final int CMD_SET_SCAN_MODE = BASE + 72;
258 /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
259 static final int CMD_SET_SCAN_TYPE = BASE + 73;
260 /* Disconnect from a network */
261 static final int CMD_DISCONNECT = BASE + 74;
262 /* Reconnect to a network */
263 static final int CMD_RECONNECT = BASE + 75;
264 /* Reassociate to a network */
265 static final int CMD_REASSOCIATE = BASE + 76;
266 /* Controls power mode and suspend mode optimizations
268 * When high perf mode is enabled, power mode is set to
269 * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
271 * When high perf mode is disabled, power mode is set to
272 * POWER_MODE_AUTO and suspend mode optimizations are enabled
274 * Suspend mode optimizations include:
277 * - DTIM wake up settings
279 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
280 /* Set the country code */
281 static final int CMD_SET_COUNTRY_CODE = BASE + 80;
282 /* Request connectivity manager wake lock before driver stop */
283 static final int CMD_REQUEST_CM_WAKELOCK = BASE + 81;
284 /* Enables RSSI poll */
285 static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
287 static final int CMD_RSSI_POLL = BASE + 83;
288 /* Set up packet filtering */
289 static final int CMD_START_PACKET_FILTERING = BASE + 84;
290 /* Clear packet filter */
291 static final int CMD_STOP_PACKET_FILTERING = BASE + 85;
292 /* Connect to a specified network (network id
293 * or WifiConfiguration) This involves increasing
294 * the priority of the network, enabling the network
295 * (while disabling others) and issuing a reconnect.
296 * Note that CMD_RECONNECT just does a reconnect to
297 * an existing network. All the networks get enabled
298 * upon a successful connection or a failure.
300 static final int CMD_CONNECT_NETWORK = BASE + 86;
301 /* Save the specified network. This involves adding
302 * an enabled network (if new) and updating the
303 * config and issuing a save on supplicant config.
305 static final int CMD_SAVE_NETWORK = BASE + 87;
306 /* Delete the specified network. This involves
307 * removing the network and issuing a save on
310 static final int CMD_FORGET_NETWORK = BASE + 88;
311 /* Start Wi-Fi protected setup */
312 static final int CMD_START_WPS = BASE + 89;
313 /* Set the frequency band */
314 static final int CMD_SET_FREQUENCY_BAND = BASE + 90;
315 /* Enable background scan for configured networks */
316 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91;
318 /* Commands from/to the SupplicantStateTracker */
319 /* Reset the supplicant state tracker */
320 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
322 /* Commands/events reported by WpsStateMachine */
323 /* Indicates the completion of WPS activity */
324 static final int WPS_COMPLETED_EVENT = BASE + 121;
325 /* Reset the WPS state machine */
326 static final int CMD_RESET_WPS_STATE = BASE + 122;
328 private static final int CONNECT_MODE = 1;
329 private static final int SCAN_ONLY_MODE = 2;
331 private static final int SCAN_ACTIVE = 1;
332 private static final int SCAN_PASSIVE = 2;
334 private static final int SUCCESS = 1;
335 private static final int FAILURE = -1;
338 * The maximum number of times we will retry a connection to an access point
339 * for which we have failed in acquiring an IP address from DHCP. A value of
340 * N means that we will make N+1 connection attempts in all.
342 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
343 * value if a Settings value is not present.
345 private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
347 static final int POWER_MODE_ACTIVE = 1;
348 static final int POWER_MODE_AUTO = 0;
350 /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
351 private int mPowerMode = POWER_MODE_AUTO;
354 * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
355 * Settings.Secure value is not present.
357 private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */
359 private static final int MIN_RSSI = -200;
360 private static final int MAX_RSSI = 256;
362 /* Constants to indicate if soft ap is running or stopped */
363 private static final int SOFT_AP_STOPPED = 0;
364 private static final int SOFT_AP_RUNNING = 1;
366 /* Default parent state */
367 private State mDefaultState = new DefaultState();
368 /* Temporary initial state */
369 private State mInitialState = new InitialState();
370 /* Unloading the driver */
371 private State mDriverUnloadingState = new DriverUnloadingState();
372 /* Loading the driver */
373 private State mDriverUnloadedState = new DriverUnloadedState();
374 /* Driver load/unload failed */
375 private State mDriverFailedState = new DriverFailedState();
377 private State mDriverLoadingState = new DriverLoadingState();
379 private State mDriverLoadedState = new DriverLoadedState();
380 /* Driver loaded, waiting for supplicant to start */
381 private State mSupplicantStartingState = new SupplicantStartingState();
382 /* Driver loaded and supplicant ready */
383 private State mSupplicantStartedState = new SupplicantStartedState();
384 /* Waiting for supplicant to stop and monitor to exit */
385 private State mSupplicantStoppingState = new SupplicantStoppingState();
386 /* Driver start issued, waiting for completed event */
387 private State mDriverStartingState = new DriverStartingState();
389 private State mDriverStartedState = new DriverStartedState();
390 /* Driver stopping */
391 private State mDriverStoppingState = new DriverStoppingState();
393 private State mDriverStoppedState = new DriverStoppedState();
394 /* Scan for networks, no connection will be established */
395 private State mScanModeState = new ScanModeState();
396 /* Connecting to an access point */
397 private State mConnectModeState = new ConnectModeState();
398 /* Fetching IP after network connection (assoc+auth complete) */
399 private State mConnectingState = new ConnectingState();
400 /* Connected with IP addr */
401 private State mConnectedState = new ConnectedState();
402 /* disconnect issued, waiting for network disconnect confirmation */
403 private State mDisconnectingState = new DisconnectingState();
404 /* Network is not connected, supplicant assoc+auth is not complete */
405 private State mDisconnectedState = new DisconnectedState();
406 /* Waiting for WPS to be completed*/
407 private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
409 /* Soft Ap is running */
410 private State mSoftApStartedState = new SoftApStartedState();
414 * One of {@link WifiManager#WIFI_STATE_DISABLED},
415 * {@link WifiManager#WIFI_STATE_DISABLING},
416 * {@link WifiManager#WIFI_STATE_ENABLED},
417 * {@link WifiManager#WIFI_STATE_ENABLING},
418 * {@link WifiManager#WIFI_STATE_UNKNOWN}
421 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
424 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
425 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
426 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
427 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
428 * {@link WifiManager#WIFI_AP_STATE_FAILED}
431 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
433 private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
434 private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
436 private static final int SCAN_REQUEST = 0;
437 private static final String ACTION_START_SCAN =
438 "com.android.server.WifiManager.action.START_SCAN";
441 * Keep track of whether WIFI is running.
443 private boolean mIsRunning = false;
446 * Keep track of whether we last told the battery stats we had started.
448 private boolean mReportedRunning = false;
451 * Most recently set source of starting WIFI.
453 private final WorkSource mRunningWifiUids = new WorkSource();
456 * The last reported UIDs that were responsible for starting WIFI.
458 private final WorkSource mLastRunningWifiUids = new WorkSource();
460 private final IBatteryStats mBatteryStats;
462 public WifiStateMachine(Context context, String wlanInterface) {
466 mInterfaceName = wlanInterface;
468 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
469 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
471 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
472 nwService = INetworkManagementService.Stub.asInterface(b);
474 mWifiMonitor = new WifiMonitor(this);
475 mDhcpInfoInternal = new DhcpInfoInternal();
476 mWifiInfo = new WifiInfo();
477 mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
478 mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
479 mLinkProperties = new LinkProperties();
481 mNetworkInfo.setIsAvailable(false);
482 mLinkProperties.clear();
484 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
485 mLastSignalLevel = -1;
487 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
488 Intent scanIntent = new Intent(ACTION_START_SCAN, null);
489 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
491 mContext.registerReceiver(
492 new BroadcastReceiver() {
494 public void onReceive(Context context, Intent intent) {
496 ArrayList<String> available = intent.getStringArrayListExtra(
497 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
498 ArrayList<String> active = intent.getStringArrayListExtra(
499 ConnectivityManager.EXTRA_ACTIVE_TETHER);
500 updateTetherState(available, active);
503 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
505 mContext.registerReceiver(
506 new BroadcastReceiver() {
508 public void onReceive(Context context, Intent intent) {
512 new IntentFilter(ACTION_START_SCAN));
514 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
516 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
517 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
519 addState(mDefaultState);
520 addState(mInitialState, mDefaultState);
521 addState(mDriverUnloadingState, mDefaultState);
522 addState(mDriverUnloadedState, mDefaultState);
523 addState(mDriverFailedState, mDriverUnloadedState);
524 addState(mDriverLoadingState, mDefaultState);
525 addState(mDriverLoadedState, mDefaultState);
526 addState(mSupplicantStartingState, mDefaultState);
527 addState(mSupplicantStartedState, mDefaultState);
528 addState(mDriverStartingState, mSupplicantStartedState);
529 addState(mDriverStartedState, mSupplicantStartedState);
530 addState(mScanModeState, mDriverStartedState);
531 addState(mConnectModeState, mDriverStartedState);
532 addState(mConnectingState, mConnectModeState);
533 addState(mConnectedState, mConnectModeState);
534 addState(mDisconnectingState, mConnectModeState);
535 addState(mDisconnectedState, mConnectModeState);
536 addState(mWaitForWpsCompletionState, mConnectModeState);
537 addState(mDriverStoppingState, mSupplicantStartedState);
538 addState(mDriverStoppedState, mSupplicantStartedState);
539 addState(mSupplicantStoppingState, mDefaultState);
540 addState(mSoftApStartedState, mDefaultState);
542 setInitialState(mInitialState);
544 if (DBG) setDbg(true);
546 //start the state machine
550 /*********************************************************
551 * Methods exposed for public use
552 ********************************************************/
557 public boolean syncPingSupplicant(AsyncChannel channel) {
558 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
559 boolean result = (resultMsg.arg1 != FAILURE);
567 public void startScan(boolean forceActive) {
568 sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
569 SCAN_ACTIVE : SCAN_PASSIVE, 0));
575 public void setWifiEnabled(boolean enable) {
576 mLastEnableUid.set(Binder.getCallingUid());
578 /* Argument is the state that is entered prior to load */
579 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
580 sendMessage(CMD_START_SUPPLICANT);
582 sendMessage(CMD_STOP_SUPPLICANT);
583 /* Argument is the state that is entered upon success */
584 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
591 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
592 mLastApEnableUid.set(Binder.getCallingUid());
594 /* Argument is the state that is entered prior to load */
595 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
596 sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
598 sendMessage(CMD_STOP_AP);
599 /* Argument is the state that is entered upon success */
600 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
604 public void setWifiApConfiguration(WifiConfiguration config) {
605 sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
608 public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
609 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
610 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
618 public int syncGetWifiState() {
619 return mWifiState.get();
625 public String syncGetWifiStateByName() {
626 switch (mWifiState.get()) {
627 case WIFI_STATE_DISABLING:
629 case WIFI_STATE_DISABLED:
631 case WIFI_STATE_ENABLING:
633 case WIFI_STATE_ENABLED:
635 case WIFI_STATE_UNKNOWN:
636 return "unknown state";
638 return "[invalid state]";
645 public int syncGetWifiApState() {
646 return mWifiApState.get();
652 public String syncGetWifiApStateByName() {
653 switch (mWifiApState.get()) {
654 case WIFI_AP_STATE_DISABLING:
656 case WIFI_AP_STATE_DISABLED:
658 case WIFI_AP_STATE_ENABLING:
660 case WIFI_AP_STATE_ENABLED:
662 case WIFI_AP_STATE_FAILED:
665 return "[invalid state]";
670 * Get status information for the current connection, if any.
671 * @return a {@link WifiInfo} object containing information about the current connection
674 public WifiInfo syncRequestConnectionInfo() {
678 public DhcpInfo syncGetDhcpInfo() {
679 synchronized (mDhcpInfoInternal) {
680 return mDhcpInfoInternal.makeDhcpInfo();
687 public void setDriverStart(boolean enable) {
689 sendMessage(CMD_START_DRIVER);
691 sendMessage(CMD_STOP_DRIVER);
698 public void setScanOnlyMode(boolean enable) {
700 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
702 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
709 public void setScanType(boolean active) {
711 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
713 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
720 public List<ScanResult> syncGetScanResultsList() {
725 * Disconnect from Access Point
727 public void disconnectCommand() {
728 sendMessage(CMD_DISCONNECT);
732 * Initiate a reconnection to AP
734 public void reconnectCommand() {
735 sendMessage(CMD_RECONNECT);
739 * Initiate a re-association to AP
741 public void reassociateCommand() {
742 sendMessage(CMD_REASSOCIATE);
746 * Add a network synchronously
748 * @return network id of the new network
750 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
751 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
752 int result = resultMsg.arg1;
757 public List<WifiConfiguration> syncGetConfiguredNetworks() {
758 return WifiConfigStore.getConfiguredNetworks();
764 * @param networkId id of the network to be removed
766 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
767 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
768 boolean result = (resultMsg.arg1 != FAILURE);
776 * @param netId network id of the network
777 * @param disableOthers true, if all other networks have to be disabled
778 * @return {@code true} if the operation succeeds, {@code false} otherwise
780 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
781 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
782 disableOthers ? 1 : 0);
783 boolean result = (resultMsg.arg1 != FAILURE);
791 * @param netId network id of the network
792 * @return {@code true} if the operation succeeds, {@code false} otherwise
794 public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
795 Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId);
796 boolean result = (resultMsg.arg1 != FAILURE);
802 * Blacklist a BSSID. This will avoid the AP if there are
803 * alternate APs to connect
805 * @param bssid BSSID of the network
807 public void addToBlacklist(String bssid) {
808 sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
812 * Clear the blacklist list
815 public void clearBlacklist() {
816 sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
819 public void connectNetwork(int netId) {
820 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
823 public void connectNetwork(WifiConfiguration wifiConfig) {
824 /* arg1 is used to indicate netId, force a netId value of
825 * WifiConfiguration.INVALID_NETWORK_ID when we are passing
826 * a configuration since the default value of 0 is a valid netId
828 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
832 public void saveNetwork(WifiConfiguration wifiConfig) {
833 sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig));
836 public void forgetNetwork(int netId) {
837 sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
840 public void startWps(Messenger replyTo, WpsConfiguration config) {
841 Message msg = obtainMessage(CMD_START_WPS, config);
842 msg.replyTo = replyTo;
846 public void enableRssiPolling(boolean enabled) {
847 sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
850 public void enableBackgroundScan(boolean enabled) {
851 sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
854 public void enableAllNetworks() {
855 sendMessage(CMD_ENABLE_ALL_NETWORKS);
859 * Start packet filtering
861 public void startPacketFiltering() {
862 sendMessage(CMD_START_PACKET_FILTERING);
866 * Stop packet filtering
868 public void stopPacketFiltering() {
869 sendMessage(CMD_STOP_PACKET_FILTERING);
873 * Set high performance mode of operation.
874 * Enabling would set active power mode and disable suspend optimizations;
875 * disabling would set auto power mode and enable suspend optimizations
876 * @param enable true if enable, false otherwise
878 public void setHighPerfModeEnabled(boolean enable) {
879 sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
883 * Set the country code
884 * @param countryCode following ISO 3166 format
885 * @param persist {@code true} if the setting should be remembered.
887 public void setCountryCode(String countryCode, boolean persist) {
889 Settings.Secure.putString(mContext.getContentResolver(),
890 Settings.Secure.WIFI_COUNTRY_CODE,
893 sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
897 * Set the operational frequency band
899 * @param persist {@code true} if the setting should be remembered.
901 public void setFrequencyBand(int band, boolean persist) {
903 Settings.Secure.putInt(mContext.getContentResolver(),
904 Settings.Secure.WIFI_FREQUENCY_BAND,
907 sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
911 * Returns the operational frequency band
913 public int getFrequencyBand() {
914 return mFrequencyBand.get();
918 * Returns the wifi configuration file
920 public String getConfigFile() {
921 return WifiConfigStore.getConfigFile();
925 * Send a message indicating bluetooth adapter connection state changed
927 public void sendBluetoothAdapterStateChange(int state) {
928 sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
932 * Save configuration on supplicant
934 * @return {@code true} if the operation succeeds, {@code false} otherwise
936 * TODO: deprecate this
938 public boolean syncSaveConfig(AsyncChannel channel) {
939 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
940 boolean result = (resultMsg.arg1 != FAILURE);
946 * Request a wakelock with connectivity service to
947 * keep the device awake until we hand-off from wifi
948 * to an alternate network
950 public void requestCmWakeLock() {
951 sendMessage(CMD_REQUEST_CM_WAKELOCK);
954 public void updateBatteryWorkSource(WorkSource newSource) {
955 synchronized (mRunningWifiUids) {
957 if (newSource != null) {
958 mRunningWifiUids.set(newSource);
961 if (mReportedRunning) {
962 // If the work source has changed since last time, need
963 // to remove old work from battery stats.
964 if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
965 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
967 mLastRunningWifiUids.set(mRunningWifiUids);
970 // Now being started, report it.
971 mBatteryStats.noteWifiRunning(mRunningWifiUids);
972 mLastRunningWifiUids.set(mRunningWifiUids);
973 mReportedRunning = true;
976 if (mReportedRunning) {
977 // Last reported we were running, time to stop.
978 mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
979 mLastRunningWifiUids.clear();
980 mReportedRunning = false;
983 mWakeLock.setWorkSource(newSource);
984 } catch (RemoteException ignore) {
990 public String toString() {
991 StringBuffer sb = new StringBuffer();
992 String LS = System.getProperty("line.separator");
993 sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
994 sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
995 sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
996 sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
997 sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
998 sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
999 sb.append("mLastBssid ").append(mLastBssid).append(LS);
1000 sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
1001 sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
1002 sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
1003 sb.append("Supplicant status").append(LS)
1004 .append(WifiNative.statusCommand()).append(LS).append(LS);
1006 sb.append(WifiConfigStore.dump());
1007 return sb.toString();
1010 /*********************************************************
1011 * Internal private functions
1012 ********************************************************/
1014 private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
1016 boolean wifiTethered = false;
1017 boolean wifiAvailable = false;
1019 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1020 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1023 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1026 String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1028 for (String intf : available) {
1029 for (String regex : wifiRegexs) {
1030 if (intf.matches(regex)) {
1032 InterfaceConfiguration ifcg = null;
1034 ifcg = service.getInterfaceConfig(intf);
1036 /* IP/netmask: 192.168.43.1/255.255.255.0 */
1037 ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
1038 "192.168.43.1"), 24);
1039 ifcg.interfaceFlags = "[up]";
1041 service.setInterfaceConfig(intf, ifcg);
1043 } catch (Exception e) {
1044 Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
1045 setWifiApEnabled(null, false);
1049 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1050 Log.e(TAG, "Error tethering on " + intf);
1051 setWifiApEnabled(null, false);
1061 * Set the country code from the system setting value, if any.
1063 private void setCountryCode() {
1064 String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1065 Settings.Secure.WIFI_COUNTRY_CODE);
1066 if (countryCode != null && !countryCode.isEmpty()) {
1067 setCountryCode(countryCode, false);
1069 //use driver default
1074 * Set the frequency band from the system setting value, if any.
1076 private void setFrequencyBand() {
1077 int band = Settings.Secure.getInt(mContext.getContentResolver(),
1078 Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1079 setFrequencyBand(band, false);
1082 private void setWifiState(int wifiState) {
1083 final int previousWifiState = mWifiState.get();
1086 if (wifiState == WIFI_STATE_ENABLED) {
1087 mBatteryStats.noteWifiOn();
1088 } else if (wifiState == WIFI_STATE_DISABLED) {
1089 mBatteryStats.noteWifiOff();
1091 } catch (RemoteException e) {
1092 Log.e(TAG, "Failed to note battery stats in wifi");
1095 mWifiState.set(wifiState);
1097 if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName());
1099 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1100 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1101 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1102 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1103 mContext.sendStickyBroadcast(intent);
1106 private void setWifiApState(int wifiApState) {
1107 final int previousWifiApState = mWifiApState.get();
1110 if (wifiApState == WIFI_AP_STATE_ENABLED) {
1111 mBatteryStats.noteWifiOn();
1112 } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1113 mBatteryStats.noteWifiOff();
1115 } catch (RemoteException e) {
1116 Log.d(TAG, "Failed to note battery stats in wifi");
1120 mWifiApState.set(wifiApState);
1122 if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName());
1124 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1125 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1126 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1127 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1128 mContext.sendStickyBroadcast(intent);
1132 * Parse the scan result line passed to us by wpa_supplicant (helper).
1133 * @param line the line to parse
1134 * @return the {@link ScanResult} object
1136 private ScanResult parseScanResult(String line) {
1137 ScanResult scanResult = null;
1140 * Cache implementation (LinkedHashMap) is not synchronized, thus,
1141 * must synchronized here!
1143 synchronized (mScanResultCache) {
1144 String[] result = scanResultPattern.split(line);
1145 if (3 <= result.length && result.length <= 5) {
1146 String bssid = result[0];
1147 // bssid | frequency | level | flags | ssid
1151 frequency = Integer.parseInt(result[1]);
1152 level = Integer.parseInt(result[2]);
1153 /* some implementations avoid negative values by adding 256
1154 * so we need to adjust for that here.
1156 if (level > 0) level -= 256;
1157 } catch (NumberFormatException e) {
1163 * The formatting of the results returned by
1164 * wpa_supplicant is intended to make the fields
1165 * line up nicely when printed,
1166 * not to make them easy to parse. So we have to
1167 * apply some heuristics to figure out which field
1168 * is the SSID and which field is the flags.
1172 if (result.length == 4) {
1173 if (result[3].charAt(0) == '[') {
1180 } else if (result.length == 5) {
1184 // Here, we must have 3 fields: no flags and ssid
1190 // bssid + ssid is the hash key
1191 String key = bssid + ssid;
1192 scanResult = mScanResultCache.get(key);
1193 if (scanResult != null) {
1194 scanResult.level = level;
1195 scanResult.SSID = ssid;
1196 scanResult.capabilities = flags;
1197 scanResult.frequency = frequency;
1199 // Do not add scan results that have no SSID set
1200 if (0 < ssid.trim().length()) {
1203 ssid, bssid, flags, level, frequency);
1204 mScanResultCache.put(key, scanResult);
1208 Log.w(TAG, "Misformatted scan result text with " +
1209 result.length + " fields: " + line);
1218 * scanResults input format
1219 * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1
1220 * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2
1222 private void setScanResults(String scanResults) {
1223 if (scanResults == null) {
1227 List<ScanResult> scanList = new ArrayList<ScanResult>();
1231 int scanResultsLen = scanResults.length();
1232 // Parse the result string, keeping in mind that the last line does
1233 // not end with a newline.
1234 for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
1235 if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
1238 if (lineCount == 1) {
1239 lineBeg = lineEnd + 1;
1242 if (lineEnd > lineBeg) {
1243 String line = scanResults.substring(lineBeg, lineEnd);
1244 ScanResult scanResult = parseScanResult(line);
1245 if (scanResult != null) {
1246 scanList.add(scanResult);
1248 //TODO: hidden network handling
1251 lineBeg = lineEnd + 1;
1255 mScanResults = scanList;
1258 private String fetchSSID() {
1259 String status = WifiNative.statusCommand();
1260 if (status == null) {
1263 // extract ssid from a series of "name=value"
1264 String[] lines = status.split("\n");
1265 for (String line : lines) {
1266 String[] prop = line.split(" *= *");
1267 if (prop.length < 2) continue;
1268 String name = prop[0];
1269 String value = prop[1];
1270 if (name.equalsIgnoreCase("ssid")) return value;
1276 * Fetch RSSI and linkspeed on current connection
1278 private void fetchRssiAndLinkSpeedNative() {
1279 int newRssi = WifiNative.getRssiCommand();
1280 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1281 /* some implementations avoid negative values by adding 256
1282 * so we need to adjust for that here.
1284 if (newRssi > 0) newRssi -= 256;
1285 mWifiInfo.setRssi(newRssi);
1287 * Rather then sending the raw RSSI out every time it
1288 * changes, we precalculate the signal level that would
1289 * be displayed in the status bar, and only send the
1290 * broadcast if that much more coarse-grained number
1291 * changes. This cuts down greatly on the number of
1292 * broadcasts, at the cost of not mWifiInforming others
1293 * interested in RSSI of all the changes in signal
1296 // TODO: The second arg to the call below needs to be a symbol somewhere, but
1297 // it's actually the size of an array of icons that's private
1298 // to StatusBar Policy.
1299 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
1300 if (newSignalLevel != mLastSignalLevel) {
1301 sendRssiChangeBroadcast(newRssi);
1303 mLastSignalLevel = newSignalLevel;
1305 mWifiInfo.setRssi(MIN_RSSI);
1307 int newLinkSpeed = WifiNative.getLinkSpeedCommand();
1308 if (newLinkSpeed != -1) {
1309 mWifiInfo.setLinkSpeed(newLinkSpeed);
1313 private void setHighPerfModeEnabledNative(boolean enable) {
1314 if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
1315 Log.e(TAG, "set suspend optimizations failed!");
1318 if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
1319 Log.e(TAG, "set power mode active failed!");
1322 if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
1323 Log.e(TAG, "set power mode auto failed!");
1328 private void configureLinkProperties() {
1329 if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1330 mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
1332 synchronized (mDhcpInfoInternal) {
1333 mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1335 mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1337 mLinkProperties.setInterfaceName(mInterfaceName);
1338 Log.d(TAG, "netId=" + mLastNetworkId + " Link configured: " + mLinkProperties.toString());
1341 private int getMaxDhcpRetries() {
1342 return Settings.Secure.getInt(mContext.getContentResolver(),
1343 Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1344 DEFAULT_MAX_DHCP_RETRIES);
1347 private void sendScanResultsAvailableBroadcast() {
1348 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1349 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1350 mContext.sendBroadcast(intent);
1353 private void sendRssiChangeBroadcast(final int newRssi) {
1354 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1355 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1356 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1357 mContext.sendBroadcast(intent);
1360 private void sendNetworkStateChangeBroadcast(String bssid) {
1361 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1362 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1363 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1364 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
1365 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1367 intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1368 mContext.sendStickyBroadcast(intent);
1371 private void sendErrorBroadcast(int errorCode) {
1372 Intent intent = new Intent(WifiManager.ERROR_ACTION);
1373 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1374 intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
1375 mContext.sendBroadcast(intent);
1378 private void sendLinkConfigurationChangedBroadcast() {
1379 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1380 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1381 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1382 mContext.sendBroadcast(intent);
1385 private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1386 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1387 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1388 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1389 mContext.sendBroadcast(intent);
1393 * Record the detailed state of a network.
1394 * @param state the new @{code DetailedState}
1396 private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1397 Log.d(TAG, "setDetailed state, old ="
1398 + mNetworkInfo.getDetailedState() + " and new state=" + state);
1399 if (state != mNetworkInfo.getDetailedState()) {
1400 mNetworkInfo.setDetailedState(state, null, null);
1404 private DetailedState getNetworkDetailedState() {
1405 return mNetworkInfo.getDetailedState();
1409 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1410 * using the interface, stopping DHCP & disabling interface
1412 private void handleNetworkDisconnect() {
1413 Log.d(TAG, "Reset connections and stopping DHCP");
1418 NetworkUtils.resetConnections(mInterfaceName);
1420 if (mDhcpStateMachine != null) {
1421 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1422 mDhcpStateMachine.quit();
1423 mDhcpStateMachine = null;
1426 /* Disable interface */
1427 NetworkUtils.disableInterface(mInterfaceName);
1429 /* Reset data structures */
1430 mWifiInfo.setInetAddress(null);
1431 mWifiInfo.setBSSID(null);
1432 mWifiInfo.setSSID(null);
1433 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1434 mWifiInfo.setRssi(MIN_RSSI);
1435 mWifiInfo.setLinkSpeed(-1);
1437 /* send event to CM & network change broadcast */
1438 setNetworkDetailedState(DetailedState.DISCONNECTED);
1439 sendNetworkStateChangeBroadcast(mLastBssid);
1441 /* Clear network properties */
1442 mLinkProperties.clear();
1443 /* Clear IP settings if the network used DHCP */
1444 if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1445 WifiConfigStore.clearIpConfiguration(mLastNetworkId);
1449 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1452 void handlePreDhcpSetup() {
1453 if (!mBluetoothConnectionActive) {
1455 * There are problems setting the Wi-Fi driver's power
1456 * mode to active when bluetooth coexistence mode is
1459 * We set Wi-Fi to active mode when
1460 * obtaining an IP address because we've found
1461 * compatibility issues with some routers with low power
1464 * In order for this active power mode to properly be set,
1465 * we disable coexistence mode until we're done with
1466 * obtaining an IP address. One exception is if we
1467 * are currently connected to a headset, since disabling
1468 * coexistence would interrupt that connection.
1470 // Disable the coexistence mode
1471 WifiNative.setBluetoothCoexistenceModeCommand(
1472 WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1475 mPowerMode = WifiNative.getPowerModeCommand();
1476 if (mPowerMode < 0) {
1477 // Handle the case where supplicant driver does not support
1478 // getPowerModeCommand.
1479 mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
1481 if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
1482 WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
1487 void handlePostDhcpSetup() {
1488 /* restore power mode */
1489 WifiNative.setPowerModeCommand(mPowerMode);
1491 // Set the coexistence mode back to its default value
1492 WifiNative.setBluetoothCoexistenceModeCommand(
1493 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1496 private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
1497 synchronized (mDhcpInfoInternal) {
1498 mDhcpInfoInternal = dhcpInfoInternal;
1500 mLastSignalLevel = -1; // force update of signal strength
1501 WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
1502 InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
1503 mWifiInfo.setInetAddress(addr);
1504 if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1505 //DHCP renewal in connected state
1506 LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
1507 linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1508 linkProperties.setInterfaceName(mInterfaceName);
1509 if (!linkProperties.equals(mLinkProperties)) {
1510 Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
1511 + " old: " + mLinkProperties + "new: " + linkProperties);
1512 NetworkUtils.resetConnections(mInterfaceName);
1513 mLinkProperties = linkProperties;
1514 sendLinkConfigurationChangedBroadcast();
1517 configureLinkProperties();
1518 setNetworkDetailedState(DetailedState.CONNECTED);
1519 sendNetworkStateChangeBroadcast(mLastBssid);
1523 private void handleFailedIpConfiguration() {
1524 Log.e(TAG, "IP configuration failed");
1526 mWifiInfo.setInetAddress(null);
1528 * If we've exceeded the maximum number of retries for DHCP
1529 * to a given network, disable the network
1531 if (++mReconnectCount > getMaxDhcpRetries()) {
1532 Log.e(TAG, "Failed " +
1533 mReconnectCount + " times, Disabling " + mLastNetworkId);
1534 WifiConfigStore.disableNetwork(mLastNetworkId);
1535 mReconnectCount = 0;
1538 /* DHCP times out after about 30 seconds, we do a
1539 * disconnect and an immediate reconnect to try again
1541 WifiNative.disconnectCommand();
1542 WifiNative.reconnectCommand();
1545 private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
1546 if (config == null) {
1547 config = WifiApConfigStore.getApConfiguration();
1549 WifiApConfigStore.setApConfiguration(config);
1552 if (currentStatus == SOFT_AP_STOPPED) {
1553 nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1554 } else if (currentStatus == SOFT_AP_RUNNING) {
1555 nwService.setAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1557 } catch (Exception e) {
1558 Log.e(TAG, "Exception in softap start " + e);
1560 nwService.stopAccessPoint();
1561 nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1562 } catch (Exception ee) {
1563 Log.e(TAG, "Exception during softap restart : " + ee);
1571 /*********************************************************
1572 * Notifications from WifiMonitor
1573 ********************************************************/
1576 * Stores supplicant state change information passed from WifiMonitor
1578 static class StateChangeResult {
1579 StateChangeResult(int networkId, String BSSID, SupplicantState state) {
1582 this.networkId = networkId;
1586 SupplicantState state;
1590 * Send the tracker a notification that a user provided
1591 * configuration caused authentication failure - this could
1592 * be a password failure or a EAP authentication failure
1594 void notifyAuthenticationFailure() {
1595 sendMessage(AUTHENTICATION_FAILURE_EVENT);
1599 * Send a notification that the supplicant has detected overlapped
1602 void notifyWpsOverlap() {
1603 sendMessage(WPS_OVERLAP_EVENT);
1607 * Send the tracker a notification that a connection to the supplicant
1608 * daemon has been established.
1610 void notifySupplicantConnection() {
1611 sendMessage(SUP_CONNECTION_EVENT);
1615 * Send the tracker a notification that connection to the supplicant
1618 void notifySupplicantLost() {
1619 sendMessage(SUP_DISCONNECTION_EVENT);
1623 * Send the tracker a notification that the state of Wifi connectivity
1625 * @param networkId the configured network on which the state change occurred
1626 * @param newState the new network state
1627 * @param BSSID when the new state is {@link DetailedState#CONNECTED
1628 * NetworkInfo.DetailedState.CONNECTED},
1629 * this is the MAC address of the access point. Otherwise, it
1632 void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
1633 if (newState == NetworkInfo.DetailedState.CONNECTED) {
1634 sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, networkId, 0, BSSID));
1636 sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, networkId, 0, BSSID));
1641 * Send the tracker a notification that the state of the supplicant
1643 * @param networkId the configured network on which the state change occurred
1644 * @param newState the new {@code SupplicantState}
1646 void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
1647 sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
1648 new StateChangeResult(networkId, BSSID, newState)));
1652 * Send the tracker a notification that a scan has completed, and results
1655 void notifyScanResultsAvailable() {
1657 * Switch scan mode over to passive.
1658 * Turning off scan-only mode happens only in "Connect" mode
1661 sendMessage(SCAN_RESULTS_EVENT);
1664 void notifyDriverStarted() {
1665 sendMessage(DRIVER_START_EVENT);
1668 void notifyDriverStopped() {
1669 sendMessage(DRIVER_STOP_EVENT);
1672 void notifyDriverHung() {
1673 setWifiEnabled(false);
1674 setWifiEnabled(true);
1677 /********************************************************
1679 *******************************************************/
1681 class DefaultState extends State {
1683 public boolean processMessage(Message message) {
1684 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1685 switch (message.what) {
1686 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1687 mBluetoothConnectionActive = (message.arg1 !=
1688 BluetoothAdapter.STATE_DISCONNECTED);
1690 /* Synchronous call returns */
1691 case CMD_PING_SUPPLICANT:
1692 case CMD_ENABLE_NETWORK:
1693 case CMD_DISABLE_NETWORK:
1694 case CMD_ADD_OR_UPDATE_NETWORK:
1695 case CMD_REMOVE_NETWORK:
1696 case CMD_SAVE_CONFIG:
1697 mReplyChannel.replyToMessage(message, message.what, FAILURE);
1699 case CMD_ENABLE_RSSI_POLL:
1700 mEnableRssiPolling = (message.arg1 == 1);
1702 case CMD_ENABLE_BACKGROUND_SCAN:
1703 mEnableBackgroundScan = (message.arg1 == 1);
1705 case CMD_SET_AP_CONFIG:
1706 WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
1708 case CMD_GET_AP_CONFIG:
1709 WifiConfiguration config = WifiApConfigStore.getApConfiguration();
1710 mReplyChannel.replyToMessage(message, message.what, config);
1713 case CMD_LOAD_DRIVER:
1714 case CMD_UNLOAD_DRIVER:
1715 case CMD_START_SUPPLICANT:
1716 case CMD_STOP_SUPPLICANT:
1717 case CMD_START_DRIVER:
1718 case CMD_STOP_DRIVER:
1721 case CMD_START_SCAN:
1722 case CMD_DISCONNECT:
1724 case CMD_REASSOCIATE:
1725 case SUP_CONNECTION_EVENT:
1726 case SUP_DISCONNECTION_EVENT:
1727 case DRIVER_START_EVENT:
1728 case DRIVER_STOP_EVENT:
1729 case NETWORK_CONNECTION_EVENT:
1730 case NETWORK_DISCONNECTION_EVENT:
1731 case SCAN_RESULTS_EVENT:
1732 case SUPPLICANT_STATE_CHANGE_EVENT:
1733 case AUTHENTICATION_FAILURE_EVENT:
1734 case WPS_OVERLAP_EVENT:
1735 case CMD_BLACKLIST_NETWORK:
1736 case CMD_CLEAR_BLACKLIST:
1737 case CMD_SET_SCAN_MODE:
1738 case CMD_SET_SCAN_TYPE:
1739 case CMD_SET_HIGH_PERF_MODE:
1740 case CMD_SET_COUNTRY_CODE:
1741 case CMD_SET_FREQUENCY_BAND:
1742 case CMD_REQUEST_CM_WAKELOCK:
1743 case CMD_CONNECT_NETWORK:
1744 case CMD_SAVE_NETWORK:
1745 case CMD_FORGET_NETWORK:
1747 case CMD_ENABLE_ALL_NETWORKS:
1748 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1749 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1752 /* Return failure when the state machine cannot handle WPS initiation*/
1753 mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
1754 new WpsResult(Status.FAILURE));
1757 Log.e(TAG, "Error! unhandled message" + message);
1764 class InitialState extends State {
1766 //TODO: could move logging into a common class
1767 public void enter() {
1768 if (DBG) Log.d(TAG, getName() + "\n");
1769 // [31-8] Reserved for future use
1770 // [7 - 0] HSM state change
1771 // 50021 wifi_state_changed (custom|1|5)
1772 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1774 WifiApConfigStore.initialize(mContext);
1776 if (WifiNative.isDriverLoaded()) {
1777 transitionTo(mDriverLoadedState);
1780 transitionTo(mDriverUnloadedState);
1785 class DriverLoadingState extends State {
1787 public void enter() {
1788 if (DBG) Log.d(TAG, getName() + "\n");
1789 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1791 final Message message = new Message();
1792 message.copyFrom(getCurrentMessage());
1793 /* TODO: add a timeout to fail when driver load is hung.
1794 * Similarly for driver unload.
1796 new Thread(new Runnable() {
1798 mWakeLock.acquire();
1800 switch(message.arg1) {
1801 case WIFI_STATE_ENABLING:
1802 setWifiState(WIFI_STATE_ENABLING);
1804 case WIFI_AP_STATE_ENABLING:
1805 setWifiApState(WIFI_AP_STATE_ENABLING);
1809 if(WifiNative.loadDriver()) {
1810 Log.d(TAG, "Driver load successful");
1811 sendMessage(CMD_LOAD_DRIVER_SUCCESS);
1813 Log.e(TAG, "Failed to load driver!");
1814 switch(message.arg1) {
1815 case WIFI_STATE_ENABLING:
1816 setWifiState(WIFI_STATE_UNKNOWN);
1818 case WIFI_AP_STATE_ENABLING:
1819 setWifiApState(WIFI_AP_STATE_FAILED);
1822 sendMessage(CMD_LOAD_DRIVER_FAILURE);
1824 mWakeLock.release();
1830 public boolean processMessage(Message message) {
1831 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1832 switch (message.what) {
1833 case CMD_LOAD_DRIVER_SUCCESS:
1834 transitionTo(mDriverLoadedState);
1836 case CMD_LOAD_DRIVER_FAILURE:
1837 transitionTo(mDriverFailedState);
1839 case CMD_LOAD_DRIVER:
1840 case CMD_UNLOAD_DRIVER:
1841 case CMD_START_SUPPLICANT:
1842 case CMD_STOP_SUPPLICANT:
1845 case CMD_START_DRIVER:
1846 case CMD_STOP_DRIVER:
1847 case CMD_SET_SCAN_MODE:
1848 case CMD_SET_SCAN_TYPE:
1849 case CMD_SET_HIGH_PERF_MODE:
1850 case CMD_SET_COUNTRY_CODE:
1851 case CMD_SET_FREQUENCY_BAND:
1852 case CMD_START_PACKET_FILTERING:
1853 case CMD_STOP_PACKET_FILTERING:
1854 deferMessage(message);
1859 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1864 class DriverLoadedState extends State {
1866 public void enter() {
1867 if (DBG) Log.d(TAG, getName() + "\n");
1868 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1871 public boolean processMessage(Message message) {
1872 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1873 switch(message.what) {
1874 case CMD_UNLOAD_DRIVER:
1875 transitionTo(mDriverUnloadingState);
1877 case CMD_START_SUPPLICANT:
1878 if(WifiNative.startSupplicant()) {
1879 Log.d(TAG, "Supplicant start successful");
1880 mWifiMonitor.startMonitoring();
1881 transitionTo(mSupplicantStartingState);
1883 Log.e(TAG, "Failed to start supplicant!");
1884 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
1888 if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_STOPPED)) {
1889 Log.d(TAG, "Soft AP start successful");
1890 setWifiApState(WIFI_AP_STATE_ENABLED);
1891 transitionTo(mSoftApStartedState);
1893 Log.d(TAG, "Soft AP start failed");
1894 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
1900 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1905 class DriverUnloadingState extends State {
1907 public void enter() {
1908 if (DBG) Log.d(TAG, getName() + "\n");
1909 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1911 final Message message = new Message();
1912 message.copyFrom(getCurrentMessage());
1913 new Thread(new Runnable() {
1915 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1916 mWakeLock.acquire();
1917 if(WifiNative.unloadDriver()) {
1918 Log.d(TAG, "Driver unload successful");
1919 sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
1921 switch(message.arg1) {
1922 case WIFI_STATE_DISABLED:
1923 case WIFI_STATE_UNKNOWN:
1924 setWifiState(message.arg1);
1926 case WIFI_AP_STATE_DISABLED:
1927 case WIFI_AP_STATE_FAILED:
1928 setWifiApState(message.arg1);
1932 Log.e(TAG, "Failed to unload driver!");
1933 sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
1935 switch(message.arg1) {
1936 case WIFI_STATE_DISABLED:
1937 case WIFI_STATE_UNKNOWN:
1938 setWifiState(WIFI_STATE_UNKNOWN);
1940 case WIFI_AP_STATE_DISABLED:
1941 case WIFI_AP_STATE_FAILED:
1942 setWifiApState(WIFI_AP_STATE_FAILED);
1946 mWakeLock.release();
1952 public boolean processMessage(Message message) {
1953 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1954 switch (message.what) {
1955 case CMD_UNLOAD_DRIVER_SUCCESS:
1956 transitionTo(mDriverUnloadedState);
1958 case CMD_UNLOAD_DRIVER_FAILURE:
1959 transitionTo(mDriverFailedState);
1961 case CMD_LOAD_DRIVER:
1962 case CMD_UNLOAD_DRIVER:
1963 case CMD_START_SUPPLICANT:
1964 case CMD_STOP_SUPPLICANT:
1967 case CMD_START_DRIVER:
1968 case CMD_STOP_DRIVER:
1969 case CMD_SET_SCAN_MODE:
1970 case CMD_SET_SCAN_TYPE:
1971 case CMD_SET_HIGH_PERF_MODE:
1972 case CMD_SET_COUNTRY_CODE:
1973 case CMD_SET_FREQUENCY_BAND:
1974 case CMD_START_PACKET_FILTERING:
1975 case CMD_STOP_PACKET_FILTERING:
1976 deferMessage(message);
1981 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1986 class DriverUnloadedState extends State {
1988 public void enter() {
1989 if (DBG) Log.d(TAG, getName() + "\n");
1990 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1993 public boolean processMessage(Message message) {
1994 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1995 switch (message.what) {
1996 case CMD_LOAD_DRIVER:
1997 transitionTo(mDriverLoadingState);
2002 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2007 class DriverFailedState extends State {
2009 public void enter() {
2010 Log.e(TAG, getName() + "\n");
2011 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2014 public boolean processMessage(Message message) {
2015 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2021 class SupplicantStartingState extends State {
2023 public void enter() {
2024 if (DBG) Log.d(TAG, getName() + "\n");
2025 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2028 public boolean processMessage(Message message) {
2029 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2030 switch(message.what) {
2031 case SUP_CONNECTION_EVENT:
2032 Log.d(TAG, "Supplicant connection established");
2033 setWifiState(WIFI_STATE_ENABLED);
2034 mSupplicantRestartCount = 0;
2035 /* Reset the supplicant state to indicate the supplicant
2036 * state is not known at this time */
2037 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2038 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2039 /* Initialize data structures */
2041 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2042 mLastSignalLevel = -1;
2044 mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
2046 WifiConfigStore.initialize(mContext);
2048 //TODO: initialize and fix multicast filtering
2049 //mWM.initializeMulticastFiltering();
2051 sendSupplicantConnectionChangedBroadcast(true);
2052 transitionTo(mDriverStartedState);
2054 case SUP_DISCONNECTION_EVENT:
2055 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2056 Log.e(TAG, "Failed to setup control channel, restart supplicant");
2057 WifiNative.killSupplicant();
2058 transitionTo(mDriverLoadedState);
2059 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2061 mSupplicantRestartCount = 0;
2062 Log.e(TAG, "Failed " + mSupplicantRestartCount +
2063 " times to start supplicant, unload driver");
2064 transitionTo(mDriverLoadedState);
2065 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2068 case CMD_LOAD_DRIVER:
2069 case CMD_UNLOAD_DRIVER:
2070 case CMD_START_SUPPLICANT:
2071 case CMD_STOP_SUPPLICANT:
2074 case CMD_START_DRIVER:
2075 case CMD_STOP_DRIVER:
2076 case CMD_SET_SCAN_MODE:
2077 case CMD_SET_SCAN_TYPE:
2078 case CMD_SET_HIGH_PERF_MODE:
2079 case CMD_SET_COUNTRY_CODE:
2080 case CMD_SET_FREQUENCY_BAND:
2081 case CMD_START_PACKET_FILTERING:
2082 case CMD_STOP_PACKET_FILTERING:
2083 deferMessage(message);
2088 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2093 class SupplicantStartedState extends State {
2095 public void enter() {
2096 if (DBG) Log.d(TAG, getName() + "\n");
2097 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2098 /* Initialize for connect mode operation at start */
2099 mIsScanMode = false;
2100 /* Wifi is available as long as we have a connection to supplicant */
2101 mNetworkInfo.setIsAvailable(true);
2104 public boolean processMessage(Message message) {
2105 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2106 WifiConfiguration config;
2107 boolean eventLoggingEnabled = true;
2108 switch(message.what) {
2109 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
2110 Log.d(TAG, "stopping supplicant");
2111 if (!WifiNative.stopSupplicant()) {
2112 Log.e(TAG, "Failed to stop supplicant, issue kill");
2113 WifiNative.killSupplicant();
2115 mNetworkInfo.setIsAvailable(false);
2116 handleNetworkDisconnect();
2117 setWifiState(WIFI_STATE_DISABLING);
2118 sendSupplicantConnectionChangedBroadcast(false);
2119 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2120 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2121 transitionTo(mSupplicantStoppingState);
2123 case SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
2124 Log.e(TAG, "Connection lost, restart supplicant");
2125 WifiNative.killSupplicant();
2126 WifiNative.closeSupplicantConnection();
2127 mNetworkInfo.setIsAvailable(false);
2128 handleNetworkDisconnect();
2129 sendSupplicantConnectionChangedBroadcast(false);
2130 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2131 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2132 transitionTo(mDriverLoadedState);
2133 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2135 case SCAN_RESULTS_EVENT:
2136 eventLoggingEnabled = false;
2137 setScanResults(WifiNative.scanResultsCommand());
2138 sendScanResultsAvailableBroadcast();
2139 mScanResultIsPending = false;
2141 case CMD_PING_SUPPLICANT:
2142 boolean ok = WifiNative.pingCommand();
2143 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2145 case CMD_ADD_OR_UPDATE_NETWORK:
2146 config = (WifiConfiguration) message.obj;
2147 mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2148 WifiConfigStore.addOrUpdateNetwork(config));
2150 case CMD_REMOVE_NETWORK:
2151 ok = WifiConfigStore.removeNetwork(message.arg1);
2152 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2154 case CMD_ENABLE_NETWORK:
2155 ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2156 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2158 case CMD_ENABLE_ALL_NETWORKS:
2159 WifiConfigStore.enableAllNetworks();
2161 case CMD_DISABLE_NETWORK:
2162 ok = WifiConfigStore.disableNetwork(message.arg1);
2163 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2165 case CMD_BLACKLIST_NETWORK:
2166 WifiNative.addToBlacklistCommand((String)message.obj);
2168 case CMD_CLEAR_BLACKLIST:
2169 WifiNative.clearBlacklistCommand();
2171 case CMD_SAVE_CONFIG:
2172 ok = WifiConfigStore.saveConfig();
2173 mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2175 // Inform the backup manager about a data change
2176 IBackupManager ibm = IBackupManager.Stub.asInterface(
2177 ServiceManager.getService(Context.BACKUP_SERVICE));
2180 ibm.dataChanged("com.android.providers.settings");
2181 } catch (Exception e) {
2186 /* Cannot start soft AP while in client mode */
2188 Log.d(TAG, "Failed to start soft AP with a running supplicant");
2189 setWifiApState(WIFI_AP_STATE_FAILED);
2191 case CMD_SET_SCAN_MODE:
2192 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2194 case CMD_SAVE_NETWORK:
2195 config = (WifiConfiguration) message.obj;
2196 WifiConfigStore.saveNetwork(config);
2198 case CMD_FORGET_NETWORK:
2199 WifiConfigStore.forgetNetwork(message.arg1);
2204 if (eventLoggingEnabled) {
2205 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2211 public void exit() {
2212 mNetworkInfo.setIsAvailable(false);
2216 class SupplicantStoppingState extends State {
2218 public void enter() {
2219 if (DBG) Log.d(TAG, getName() + "\n");
2220 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2223 public boolean processMessage(Message message) {
2224 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2225 switch(message.what) {
2226 case SUP_CONNECTION_EVENT:
2227 Log.e(TAG, "Supplicant connection received while stopping");
2229 case SUP_DISCONNECTION_EVENT:
2230 Log.d(TAG, "Supplicant connection lost");
2231 WifiNative.closeSupplicantConnection();
2232 transitionTo(mDriverLoadedState);
2234 case CMD_LOAD_DRIVER:
2235 case CMD_UNLOAD_DRIVER:
2236 case CMD_START_SUPPLICANT:
2237 case CMD_STOP_SUPPLICANT:
2240 case CMD_START_DRIVER:
2241 case CMD_STOP_DRIVER:
2242 case CMD_SET_SCAN_MODE:
2243 case CMD_SET_SCAN_TYPE:
2244 case CMD_SET_HIGH_PERF_MODE:
2245 case CMD_SET_COUNTRY_CODE:
2246 case CMD_SET_FREQUENCY_BAND:
2247 case CMD_START_PACKET_FILTERING:
2248 case CMD_STOP_PACKET_FILTERING:
2249 deferMessage(message);
2254 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2259 class DriverStartingState extends State {
2261 public void enter() {
2262 if (DBG) Log.d(TAG, getName() + "\n");
2263 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2266 public boolean processMessage(Message message) {
2267 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2268 switch(message.what) {
2269 case DRIVER_START_EVENT:
2270 transitionTo(mDriverStartedState);
2272 /* Queue driver commands & connection events */
2273 case CMD_START_DRIVER:
2274 case CMD_STOP_DRIVER:
2275 case SUPPLICANT_STATE_CHANGE_EVENT:
2276 case NETWORK_CONNECTION_EVENT:
2277 case NETWORK_DISCONNECTION_EVENT:
2278 case AUTHENTICATION_FAILURE_EVENT:
2279 case WPS_OVERLAP_EVENT:
2280 case CMD_SET_SCAN_TYPE:
2281 case CMD_SET_HIGH_PERF_MODE:
2282 case CMD_SET_COUNTRY_CODE:
2283 case CMD_SET_FREQUENCY_BAND:
2284 case CMD_START_PACKET_FILTERING:
2285 case CMD_STOP_PACKET_FILTERING:
2286 case CMD_START_SCAN:
2287 case CMD_DISCONNECT:
2288 case CMD_REASSOCIATE:
2290 deferMessage(message);
2295 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2300 class DriverStartedState extends State {
2302 public void enter() {
2303 if (DBG) Log.d(TAG, getName() + "\n");
2304 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2307 updateBatteryWorkSource(null);
2310 * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2311 * When this mode is on, some of the low-level scan parameters used by the
2312 * driver are changed to reduce interference with bluetooth
2314 WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2315 /* set country code */
2317 /* set frequency band of operation */
2319 /* initialize network state */
2320 setNetworkDetailedState(DetailedState.DISCONNECTED);
2323 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2324 WifiNative.disconnectCommand();
2325 transitionTo(mScanModeState);
2327 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2328 WifiNative.reconnectCommand();
2329 transitionTo(mDisconnectedState);
2333 public boolean processMessage(Message message) {
2334 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2335 boolean eventLoggingEnabled = true;
2336 switch(message.what) {
2337 case CMD_SET_SCAN_TYPE:
2338 if (message.arg1 == SCAN_ACTIVE) {
2339 WifiNative.setScanModeCommand(true);
2341 WifiNative.setScanModeCommand(false);
2344 case CMD_START_SCAN:
2345 eventLoggingEnabled = false;
2346 WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
2347 mScanResultIsPending = true;
2349 case CMD_SET_HIGH_PERF_MODE:
2350 setHighPerfModeEnabledNative(message.arg1 == 1);
2352 case CMD_SET_COUNTRY_CODE:
2353 String country = (String) message.obj;
2354 Log.d(TAG, "set country code " + country);
2355 if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) {
2356 Log.e(TAG, "Failed to set country code " + country);
2359 case CMD_SET_FREQUENCY_BAND:
2360 int band = message.arg1;
2361 Log.d(TAG, "set frequency band " + band);
2362 if (WifiNative.setBandCommand(band)) {
2363 mFrequencyBand.set(band);
2364 //Fetch the latest scan results when frequency band is set
2367 Log.e(TAG, "Failed to set frequency band " + band);
2370 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2371 mBluetoothConnectionActive = (message.arg1 !=
2372 BluetoothAdapter.STATE_DISCONNECTED);
2373 WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2375 case CMD_STOP_DRIVER:
2376 mWakeLock.acquire();
2377 WifiNative.stopDriverCommand();
2378 transitionTo(mDriverStoppingState);
2379 mWakeLock.release();
2381 case CMD_START_PACKET_FILTERING:
2382 WifiNative.startPacketFiltering();
2384 case CMD_STOP_PACKET_FILTERING:
2385 WifiNative.stopPacketFiltering();
2390 if (eventLoggingEnabled) {
2391 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2396 public void exit() {
2397 if (DBG) Log.d(TAG, getName() + "\n");
2399 updateBatteryWorkSource(null);
2400 mScanResults = null;
2404 class DriverStoppingState extends State {
2406 public void enter() {
2407 if (DBG) Log.d(TAG, getName() + "\n");
2408 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2411 public boolean processMessage(Message message) {
2412 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2413 switch(message.what) {
2414 case DRIVER_STOP_EVENT:
2415 transitionTo(mDriverStoppedState);
2417 /* Queue driver commands */
2418 case CMD_START_DRIVER:
2419 case CMD_STOP_DRIVER:
2420 case CMD_SET_SCAN_TYPE:
2421 case CMD_SET_HIGH_PERF_MODE:
2422 case CMD_SET_COUNTRY_CODE:
2423 case CMD_SET_FREQUENCY_BAND:
2424 case CMD_START_PACKET_FILTERING:
2425 case CMD_STOP_PACKET_FILTERING:
2426 case CMD_START_SCAN:
2427 case CMD_DISCONNECT:
2428 case CMD_REASSOCIATE:
2430 deferMessage(message);
2435 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2440 class DriverStoppedState extends State {
2442 public void enter() {
2443 if (DBG) Log.d(TAG, getName() + "\n");
2444 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2447 public boolean processMessage(Message message) {
2448 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2449 switch (message.what) {
2450 case CMD_START_DRIVER:
2451 mWakeLock.acquire();
2452 WifiNative.startDriverCommand();
2453 transitionTo(mDriverStartingState);
2454 mWakeLock.release();
2459 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2464 class ScanModeState extends State {
2466 public void enter() {
2467 if (DBG) Log.d(TAG, getName() + "\n");
2468 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2471 public boolean processMessage(Message message) {
2472 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2473 switch(message.what) {
2474 case CMD_SET_SCAN_MODE:
2475 if (message.arg1 == SCAN_ONLY_MODE) {
2479 WifiNative.setScanResultHandlingCommand(message.arg1);
2480 WifiNative.reconnectCommand();
2481 mIsScanMode = false;
2482 transitionTo(mDisconnectedState);
2486 case CMD_DISCONNECT:
2488 case CMD_REASSOCIATE:
2489 case SUPPLICANT_STATE_CHANGE_EVENT:
2490 case NETWORK_CONNECTION_EVENT:
2491 case NETWORK_DISCONNECTION_EVENT:
2496 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2501 class ConnectModeState extends State {
2503 public void enter() {
2504 if (DBG) Log.d(TAG, getName() + "\n");
2505 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2508 public boolean processMessage(Message message) {
2509 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2510 StateChangeResult stateChangeResult;
2511 switch(message.what) {
2512 case AUTHENTICATION_FAILURE_EVENT:
2513 mSupplicantStateTracker.sendMessage(AUTHENTICATION_FAILURE_EVENT);
2515 case WPS_OVERLAP_EVENT:
2516 /* We just need to broadcast the error */
2517 sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
2519 case SUPPLICANT_STATE_CHANGE_EVENT:
2520 stateChangeResult = (StateChangeResult) message.obj;
2521 SupplicantState state = stateChangeResult.state;
2522 // Supplicant state change
2523 // [31-13] Reserved for future use
2524 // [8 - 0] Supplicant state (as defined in SupplicantState.java)
2525 // 50023 supplicant_state_changed (custom|1|5)
2526 EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
2527 mWifiInfo.setSupplicantState(state);
2528 // Network id is only valid when we start connecting
2529 if (SupplicantState.isConnecting(state)) {
2530 mWifiInfo.setNetworkId(stateChangeResult.networkId);
2532 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2535 if (state == SupplicantState.ASSOCIATING) {
2536 /* BSSID is valid only in ASSOCIATING state */
2537 mWifiInfo.setBSSID(stateChangeResult.BSSID);
2540 mSupplicantStateTracker.sendMessage(Message.obtain(message));
2541 mWpsStateMachine.sendMessage(Message.obtain(message));
2543 /* Do a redundant disconnect without transition */
2544 case CMD_DISCONNECT:
2545 WifiNative.disconnectCommand();
2548 WifiNative.reconnectCommand();
2550 case CMD_REASSOCIATE:
2551 WifiNative.reassociateCommand();
2553 case CMD_CONNECT_NETWORK:
2554 int netId = message.arg1;
2555 WifiConfiguration config = (WifiConfiguration) message.obj;
2557 /* We connect to a specific network by issuing a select
2558 * to the WifiConfigStore. This enables the network,
2559 * while disabling all other networks in the supplicant.
2560 * Disabling a connected network will cause a disconnection
2561 * from the network. A reconnectCommand() will then initiate
2562 * a connection to the enabled network.
2564 if (config != null) {
2565 WifiConfigStore.selectNetwork(config);
2567 WifiConfigStore.selectNetwork(netId);
2570 /* The state tracker handles enabling networks upon completion/failure */
2571 mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
2573 WifiNative.reconnectCommand();
2575 /* Expect a disconnection from the old connection */
2576 transitionTo(mDisconnectingState);
2579 mWpsStateMachine.sendMessage(Message.obtain(message));
2580 transitionTo(mWaitForWpsCompletionState);
2582 case SCAN_RESULTS_EVENT:
2583 /* Set the scan setting back to "connect" mode */
2584 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2585 /* Handle scan results */
2587 case NETWORK_CONNECTION_EVENT:
2588 Log.d(TAG,"Network connection established");
2589 mLastNetworkId = message.arg1;
2590 mLastBssid = (String) message.obj;
2592 //TODO: make supplicant modification to push this in events
2593 mWifiInfo.setSSID(fetchSSID());
2594 mWifiInfo.setBSSID(mLastBssid);
2595 mWifiInfo.setNetworkId(mLastNetworkId);
2596 /* send event to CM & network change broadcast */
2597 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
2598 sendNetworkStateChangeBroadcast(mLastBssid);
2599 transitionTo(mConnectingState);
2601 case NETWORK_DISCONNECTION_EVENT:
2602 Log.d(TAG,"Network connection lost");
2603 handleNetworkDisconnect();
2604 transitionTo(mDisconnectedState);
2609 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2614 class ConnectingState extends State {
2617 public void enter() {
2618 if (DBG) Log.d(TAG, getName() + "\n");
2619 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2621 if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
2623 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
2624 mContext, WifiStateMachine.this, mInterfaceName);
2625 mDhcpStateMachine.registerForPreDhcpNotification();
2626 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
2628 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
2630 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
2631 INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b);
2632 InterfaceConfiguration ifcg = new InterfaceConfiguration();
2633 ifcg.addr = dhcpInfoInternal.makeLinkAddress();
2634 ifcg.interfaceFlags = "[up]";
2636 netd.setInterfaceConfig(mInterfaceName, ifcg);
2637 Log.v(TAG, "Static IP configuration succeeded");
2638 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
2639 } catch (RemoteException re) {
2640 Log.v(TAG, "Static IP configuration failed: " + re);
2641 sendMessage(CMD_STATIC_IP_FAILURE);
2642 } catch (IllegalStateException e) {
2643 Log.v(TAG, "Static IP configuration failed: " + e);
2644 sendMessage(CMD_STATIC_IP_FAILURE);
2649 public boolean processMessage(Message message) {
2650 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2652 switch(message.what) {
2653 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2654 handlePreDhcpSetup();
2655 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2657 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2658 handlePostDhcpSetup();
2659 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2660 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2661 transitionTo(mConnectedState);
2662 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2663 handleFailedIpConfiguration();
2664 transitionTo(mDisconnectingState);
2667 case CMD_STATIC_IP_SUCCESS:
2668 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2669 transitionTo(mConnectedState);
2671 case CMD_STATIC_IP_FAILURE:
2672 handleFailedIpConfiguration();
2673 transitionTo(mDisconnectingState);
2675 case CMD_DISCONNECT:
2676 WifiNative.disconnectCommand();
2677 transitionTo(mDisconnectingState);
2679 /* Ignore connection to same network */
2680 case CMD_CONNECT_NETWORK:
2681 int netId = message.arg1;
2682 if (mWifiInfo.getNetworkId() == netId) {
2686 case CMD_SAVE_NETWORK:
2687 deferMessage(message);
2690 case NETWORK_CONNECTION_EVENT:
2692 case CMD_STOP_DRIVER:
2693 sendMessage(CMD_DISCONNECT);
2694 deferMessage(message);
2696 case CMD_SET_SCAN_MODE:
2697 if (message.arg1 == SCAN_ONLY_MODE) {
2698 sendMessage(CMD_DISCONNECT);
2699 deferMessage(message);
2702 /* Defer scan when IP is being fetched */
2703 case CMD_START_SCAN:
2704 deferMessage(message);
2706 /* Defer any power mode changes since we must keep active power mode at DHCP */
2707 case CMD_SET_HIGH_PERF_MODE:
2708 deferMessage(message);
2713 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2718 class ConnectedState extends State {
2720 public void enter() {
2721 if (DBG) Log.d(TAG, getName() + "\n");
2722 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2724 if (mEnableRssiPolling) {
2725 sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0));
2729 public boolean processMessage(Message message) {
2730 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2731 boolean eventLoggingEnabled = true;
2732 switch (message.what) {
2733 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2734 handlePreDhcpSetup();
2735 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2737 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2738 handlePostDhcpSetup();
2739 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2740 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2741 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2742 handleFailedIpConfiguration();
2743 transitionTo(mDisconnectingState);
2746 case CMD_DISCONNECT:
2747 WifiNative.disconnectCommand();
2748 transitionTo(mDisconnectingState);
2750 case CMD_STOP_DRIVER:
2751 sendMessage(CMD_DISCONNECT);
2752 deferMessage(message);
2754 case CMD_REQUEST_CM_WAKELOCK:
2756 mCm = (ConnectivityManager)mContext.getSystemService(
2757 Context.CONNECTIVITY_SERVICE);
2759 mCm.requestNetworkTransitionWakelock(TAG);
2761 case CMD_SET_SCAN_MODE:
2762 if (message.arg1 == SCAN_ONLY_MODE) {
2763 sendMessage(CMD_DISCONNECT);
2764 deferMessage(message);
2767 case CMD_START_SCAN:
2768 eventLoggingEnabled = false;
2769 /* When the network is connected, re-scanning can trigger
2770 * a reconnection. Put it in scan-only mode during scan.
2771 * When scan results are received, the mode is switched
2772 * back to CONNECT_MODE.
2774 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2775 /* Have the parent state handle the rest */
2777 /* Ignore connection to same network */
2778 case CMD_CONNECT_NETWORK:
2779 int netId = message.arg1;
2780 if (mWifiInfo.getNetworkId() == netId) {
2784 case CMD_SAVE_NETWORK:
2785 WifiConfiguration config = (WifiConfiguration) message.obj;
2786 NetworkUpdateResult result = WifiConfigStore.saveNetwork(config);
2787 if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
2788 if (result.hasIpChanged()) {
2789 Log.d(TAG,"Reconfiguring IP on connection");
2790 transitionTo(mConnectingState);
2792 if (result.hasProxyChanged()) {
2793 Log.d(TAG,"Reconfiguring proxy on connection");
2794 configureLinkProperties();
2795 sendLinkConfigurationChangedBroadcast();
2800 case NETWORK_CONNECTION_EVENT:
2803 eventLoggingEnabled = false;
2804 if (message.arg1 == mRssiPollToken) {
2805 // Get Info and continue polling
2806 fetchRssiAndLinkSpeedNative();
2807 sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2808 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2810 // Polling has completed
2813 case CMD_ENABLE_RSSI_POLL:
2814 mEnableRssiPolling = (message.arg1 == 1);
2816 if (mEnableRssiPolling) {
2818 fetchRssiAndLinkSpeedNative();
2819 sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2820 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2826 if (eventLoggingEnabled) {
2827 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2832 public void exit() {
2833 /* If a scan result is pending in connected state, the supplicant
2834 * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
2836 if (mScanResultIsPending) {
2837 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2842 class DisconnectingState extends State {
2844 public void enter() {
2845 if (DBG) Log.d(TAG, getName() + "\n");
2846 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2849 public boolean processMessage(Message message) {
2850 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2851 switch (message.what) {
2852 case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
2853 deferMessage(message);
2855 case CMD_SET_SCAN_MODE:
2856 if (message.arg1 == SCAN_ONLY_MODE) {
2857 deferMessage(message);
2860 /* Handle in DisconnectedState */
2861 case SUPPLICANT_STATE_CHANGE_EVENT:
2862 deferMessage(message);
2867 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2872 class DisconnectedState extends State {
2873 private boolean mAlarmEnabled = false;
2874 private long mScanIntervalMs;
2876 private void setScanAlarm(boolean enabled) {
2877 if (enabled == mAlarmEnabled) return;
2879 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
2880 System.currentTimeMillis() + mScanIntervalMs,
2884 mAlarmEnabled = true;
2886 mAlarmManager.cancel(mScanIntent);
2887 mAlarmEnabled = false;
2892 public void enter() {
2893 if (DBG) Log.d(TAG, getName() + "\n");
2894 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2896 mScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2897 Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
2899 * We initiate background scanning if it is enabled, otherwise we
2900 * initiate an infrequent scan that wakes up the device to ensure
2901 * a user connects to an access point on the move
2903 if (mEnableBackgroundScan) {
2904 /* If a regular scan result is pending, do not initiate background
2905 * scan until the scan results are returned. This is needed because
2906 * initiating a background scan will cancel the regular scan and
2907 * scan results will not be returned until background scanning is
2910 if (!mScanResultIsPending) {
2911 WifiNative.enableBackgroundScan(true);
2918 public boolean processMessage(Message message) {
2919 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2920 switch (message.what) {
2921 case CMD_SET_SCAN_MODE:
2922 if (message.arg1 == SCAN_ONLY_MODE) {
2923 WifiNative.setScanResultHandlingCommand(message.arg1);
2924 //Supplicant disconnect to prevent further connects
2925 WifiNative.disconnectCommand();
2927 transitionTo(mScanModeState);
2930 case CMD_ENABLE_BACKGROUND_SCAN:
2931 mEnableBackgroundScan = (message.arg1 == 1);
2932 if (mEnableBackgroundScan) {
2933 WifiNative.enableBackgroundScan(true);
2934 setScanAlarm(false);
2936 WifiNative.enableBackgroundScan(false);
2940 /* Ignore network disconnect */
2941 case NETWORK_DISCONNECTION_EVENT:
2943 case SUPPLICANT_STATE_CHANGE_EVENT:
2944 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2945 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
2946 /* DriverStartedState does the rest of the handling */
2948 case CMD_START_SCAN:
2949 /* Disable background scan temporarily during a regular scan */
2950 if (mEnableBackgroundScan) {
2951 WifiNative.enableBackgroundScan(false);
2953 /* Handled in parent state */
2955 case SCAN_RESULTS_EVENT:
2956 /* Re-enable background scan when a pending scan result is received */
2957 if (mEnableBackgroundScan && mScanResultIsPending) {
2958 WifiNative.enableBackgroundScan(true);
2960 /* Handled in parent state */
2965 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2970 public void exit() {
2971 /* No need for a background scan upon exit from a disconnected state */
2972 if (mEnableBackgroundScan) {
2973 WifiNative.enableBackgroundScan(false);
2975 setScanAlarm(false);
2979 class WaitForWpsCompletionState extends State {
2981 public void enter() {
2982 if (DBG) Log.d(TAG, getName() + "\n");
2983 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2986 public boolean processMessage(Message message) {
2987 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2988 switch (message.what) {
2989 /* Defer all commands that can cause connections to a different network
2990 * or put the state machine out of connect mode
2992 case CMD_STOP_DRIVER:
2993 case CMD_SET_SCAN_MODE:
2994 case CMD_CONNECT_NETWORK:
2995 case CMD_ENABLE_NETWORK:
2997 case CMD_REASSOCIATE:
2998 case NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */
2999 deferMessage(message);
3001 case NETWORK_DISCONNECTION_EVENT:
3002 Log.d(TAG,"Network connection lost");
3003 handleNetworkDisconnect();
3005 case WPS_COMPLETED_EVENT:
3006 /* we are still disconnected until we see a network connection
3008 transitionTo(mDisconnectedState);
3013 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3018 class SoftApStartedState extends State {
3020 public void enter() {
3021 if (DBG) Log.d(TAG, getName() + "\n");
3022 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3025 public boolean processMessage(Message message) {
3026 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3027 switch(message.what) {
3029 Log.d(TAG,"Stopping Soft AP");
3030 setWifiApState(WIFI_AP_STATE_DISABLING);
3033 mCm = (ConnectivityManager) mContext.getSystemService(
3034 Context.CONNECTIVITY_SERVICE);
3036 if (mCm.untether(SOFTAP_IFACE) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
3037 Log.e(TAG, "Untether initiate failed!");
3040 nwService.stopAccessPoint();
3041 } catch(Exception e) {
3042 Log.e(TAG, "Exception in stopAccessPoint()");
3044 transitionTo(mDriverLoadedState);
3047 Log.d(TAG,"SoftAP set on a running access point");
3048 if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_RUNNING)) {
3049 Log.d(TAG, "Soft AP start successful");
3050 setWifiApState(WIFI_AP_STATE_ENABLED);
3051 transitionTo(mSoftApStartedState);
3053 Log.d(TAG, "Soft AP start failed");
3054 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
3057 /* Fail client mode operation when soft AP is enabled */
3058 case CMD_START_SUPPLICANT:
3059 Log.e(TAG,"Cannot start supplicant with a running soft AP");
3060 setWifiState(WIFI_STATE_UNKNOWN);
3065 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);