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;
27 * Deprecate WIFI_STATE_UNKNOWN
29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
31 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
32 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
33 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
35 import android.app.AlarmManager;
36 import android.app.PendingIntent;
37 import android.app.backup.IBackupManager;
38 import android.bluetooth.BluetoothAdapter;
39 import android.content.BroadcastReceiver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.pm.PackageManager;
44 import android.database.ContentObserver;
45 import android.net.ConnectivityManager;
46 import android.net.DhcpResults;
47 import android.net.DhcpStateMachine;
48 import android.net.InterfaceConfiguration;
49 import android.net.LinkAddress;
50 import android.net.LinkProperties;
51 import android.net.NetworkInfo;
52 import android.net.NetworkInfo.DetailedState;
53 import android.net.NetworkUtils;
54 import android.net.wifi.WpsResult.Status;
55 import android.net.wifi.p2p.WifiP2pManager;
56 import android.net.wifi.p2p.WifiP2pService;
57 import android.os.Binder;
58 import android.os.IBinder;
59 import android.os.INetworkManagementService;
60 import android.os.Message;
61 import android.os.Messenger;
62 import android.os.PowerManager;
63 import android.os.Process;
64 import android.os.RemoteException;
65 import android.os.ServiceManager;
66 import android.os.SystemProperties;
67 import android.os.UserHandle;
68 import android.os.WorkSource;
69 import android.provider.Settings;
70 import android.util.LruCache;
71 import android.text.TextUtils;
73 import com.android.internal.R;
74 import com.android.internal.app.IBatteryStats;
75 import com.android.internal.util.AsyncChannel;
76 import com.android.internal.util.Protocol;
77 import com.android.internal.util.State;
78 import com.android.internal.util.StateMachine;
80 import java.io.FileDescriptor;
81 import java.io.PrintWriter;
82 import java.net.InetAddress;
83 import java.util.ArrayList;
84 import java.util.List;
85 import java.util.concurrent.atomic.AtomicInteger;
86 import java.util.concurrent.atomic.AtomicBoolean;
87 import java.util.Iterator;
88 import java.util.regex.Pattern;
91 * Track the state of Wifi connectivity. All event handling is done here,
92 * and all changes in connectivity state are initiated here.
94 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
95 * In the current implementation, we support concurrent wifi p2p and wifi operation.
96 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
97 * handles p2p operation.
101 public class WifiStateMachine extends StateMachine {
103 private static final String NETWORKTYPE = "WIFI";
104 private static final boolean DBG = false;
106 private WifiMonitor mWifiMonitor;
107 private WifiNative mWifiNative;
108 private WifiConfigStore mWifiConfigStore;
109 private INetworkManagementService mNwService;
110 private ConnectivityManager mCm;
112 private final boolean mP2pSupported;
113 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
114 private boolean mTemporarilyDisconnectWifi = false;
115 private final String mPrimaryDeviceType;
117 /* Scan results handling */
118 private List<ScanResult> mScanResults = new ArrayList<ScanResult>();
119 private static final Pattern scanResultPattern = Pattern.compile("\t+");
120 private static final int SCAN_RESULT_CACHE_SIZE = 80;
121 private final LruCache<String, ScanResult> mScanResultCache;
123 /* Chipset supports background scan */
124 private final boolean mBackgroundScanSupported;
126 private String mInterfaceName;
127 /* Tethering interface could be separate from wlan interface */
128 private String mTetherInterfaceName;
130 private int mLastSignalLevel = -1;
131 private String mLastBssid;
132 private int mLastNetworkId;
133 private boolean mEnableRssiPolling = false;
134 private boolean mEnableBackgroundScan = false;
135 private int mRssiPollToken = 0;
136 private int mReconnectCount = 0;
137 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
138 * In CONNECT_MODE, the STA can scan and connect to an access point
139 * In SCAN_ONLY_MODE, the STA can only scan for access points
140 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
142 private int mOperationalMode = CONNECT_MODE;
143 private boolean mScanResultIsPending = false;
144 private WorkSource mScanWorkSource = null;
145 private static final int UNKNOWN_SCAN_SOURCE = -1;
146 /* Tracks if state machine has received any screen state change broadcast yet.
147 * We can miss one of these at boot.
149 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false);
151 private boolean mBluetoothConnectionActive = false;
153 private PowerManager.WakeLock mSuspendWakeLock;
156 * Interval in milliseconds between polling for RSSI
157 * and linkspeed information
159 private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
162 * Delay between supplicant restarts upon failure to establish connection
164 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
167 * Number of times we attempt to restart supplicant
169 private static final int SUPPLICANT_RESTART_TRIES = 5;
171 private int mSupplicantRestartCount = 0;
172 /* Tracks sequence number on stop failure message */
173 private int mSupplicantStopFailureToken = 0;
176 * Tether state change notification time out
178 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
180 /* Tracks sequence number on a tether notification time out */
181 private int mTetherToken = 0;
184 * Driver start time out.
186 private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
188 /* Tracks sequence number on a driver time out */
189 private int mDriverStartToken = 0;
191 private LinkProperties mLinkProperties;
193 /* Tracks sequence number on a periodic scan message */
194 private int mPeriodicScanToken = 0;
196 // Wakelock held during wifi start/stop and driver load/unload
197 private PowerManager.WakeLock mWakeLock;
199 private Context mContext;
201 private final Object mDhcpResultsLock = new Object();
202 private DhcpResults mDhcpResults;
203 private WifiInfo mWifiInfo;
204 private NetworkInfo mNetworkInfo;
205 private SupplicantStateTracker mSupplicantStateTracker;
206 private DhcpStateMachine mDhcpStateMachine;
208 private AlarmManager mAlarmManager;
209 private PendingIntent mScanIntent;
210 private PendingIntent mDriverStopIntent;
212 /* Tracks current frequency mode */
213 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
215 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
216 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
218 // Channel for sending replies.
219 private AsyncChannel mReplyChannel = new AsyncChannel();
221 private WifiP2pManager mWifiP2pManager;
222 //Used to initiate a connection with WifiP2pService
223 private AsyncChannel mWifiP2pChannel;
224 private AsyncChannel mWifiApConfigChannel;
226 /* The base for wifi message types */
227 static final int BASE = Protocol.BASE_WIFI;
228 /* Start the supplicant */
229 static final int CMD_START_SUPPLICANT = BASE + 11;
230 /* Stop the supplicant */
231 static final int CMD_STOP_SUPPLICANT = BASE + 12;
232 /* Start the driver */
233 static final int CMD_START_DRIVER = BASE + 13;
234 /* Stop the driver */
235 static final int CMD_STOP_DRIVER = BASE + 14;
236 /* Indicates Static IP succeeded */
237 static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
238 /* Indicates Static IP failed */
239 static final int CMD_STATIC_IP_FAILURE = BASE + 16;
240 /* Indicates supplicant stop failed */
241 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17;
242 /* Delayed stop to avoid shutting down driver too quick*/
243 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18;
244 /* A delayed message sent to start driver when it fail to come up */
245 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19;
246 /* Ready to switch to network as default */
247 static final int CMD_CAPTIVE_CHECK_COMPLETE = BASE + 20;
249 /* Start the soft access point */
250 static final int CMD_START_AP = BASE + 21;
251 /* Indicates soft ap start succeeded */
252 static final int CMD_START_AP_SUCCESS = BASE + 22;
253 /* Indicates soft ap start failed */
254 static final int CMD_START_AP_FAILURE = BASE + 23;
255 /* Stop the soft access point */
256 static final int CMD_STOP_AP = BASE + 24;
257 /* Set the soft access point configuration */
258 static final int CMD_SET_AP_CONFIG = BASE + 25;
259 /* Soft access point configuration set completed */
260 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26;
261 /* Request the soft access point configuration */
262 static final int CMD_REQUEST_AP_CONFIG = BASE + 27;
263 /* Response to access point configuration request */
264 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28;
265 /* Invoked when getting a tether state change notification */
266 static final int CMD_TETHER_STATE_CHANGE = BASE + 29;
267 /* A delayed message sent to indicate tether state change failed to arrive */
268 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30;
270 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31;
272 /* Supplicant commands */
273 /* Is supplicant alive ? */
274 static final int CMD_PING_SUPPLICANT = BASE + 51;
275 /* Add/update a network configuration */
276 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52;
277 /* Delete a network */
278 static final int CMD_REMOVE_NETWORK = BASE + 53;
279 /* Enable a network. The device will attempt a connection to the given network. */
280 static final int CMD_ENABLE_NETWORK = BASE + 54;
281 /* Enable all networks */
282 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55;
283 /* Blacklist network. De-prioritizes the given BSSID for connection. */
284 static final int CMD_BLACKLIST_NETWORK = BASE + 56;
285 /* Clear the blacklist network list */
286 static final int CMD_CLEAR_BLACKLIST = BASE + 57;
287 /* Save configuration */
288 static final int CMD_SAVE_CONFIG = BASE + 58;
289 /* Get configured networks*/
290 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59;
292 /* Supplicant commands after driver start*/
293 /* Initiate a scan */
294 static final int CMD_START_SCAN = BASE + 71;
295 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
296 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72;
297 /* Disconnect from a network */
298 static final int CMD_DISCONNECT = BASE + 73;
299 /* Reconnect to a network */
300 static final int CMD_RECONNECT = BASE + 74;
301 /* Reassociate to a network */
302 static final int CMD_REASSOCIATE = BASE + 75;
303 /* Controls suspend mode optimizations
305 * When high perf mode is enabled, suspend mode optimizations are disabled
307 * When high perf mode is disabled, suspend mode optimizations are enabled
309 * Suspend mode optimizations include:
312 * - DTIM wake up settings
314 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
315 /* Set the country code */
316 static final int CMD_SET_COUNTRY_CODE = BASE + 80;
317 /* Enables RSSI poll */
318 static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
320 static final int CMD_RSSI_POLL = BASE + 83;
321 /* Set up packet filtering */
322 static final int CMD_START_PACKET_FILTERING = BASE + 84;
323 /* Clear packet filter */
324 static final int CMD_STOP_PACKET_FILTERING = BASE + 85;
325 /* Enable suspend mode optimizations in the driver */
326 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86;
327 /* When there are no saved networks, we do a periodic scan to notify user of
329 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88;
331 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
332 static final int MULTICAST_V6 = 1;
333 static final int MULTICAST_V4 = 0;
335 /* Set the frequency band */
336 static final int CMD_SET_FREQUENCY_BAND = BASE + 90;
337 /* Enable background scan for configured networks */
338 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91;
340 /* Commands from/to the SupplicantStateTracker */
341 /* Reset the supplicant state tracker */
342 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
345 /* We are ok with no response here since we wont do much with it anyway */
346 public static final int CMD_ENABLE_P2P = BASE + 131;
347 /* In order to shut down supplicant cleanly, we wait till p2p has
349 public static final int CMD_DISABLE_P2P_REQ = BASE + 132;
350 public static final int CMD_DISABLE_P2P_RSP = BASE + 133;
352 public static final int CMD_BOOT_COMPLETED = BASE + 134;
354 public static final int CONNECT_MODE = 1;
355 public static final int SCAN_ONLY_MODE = 2;
356 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
358 private static final int SUCCESS = 1;
359 private static final int FAILURE = -1;
362 * The maximum number of times we will retry a connection to an access point
363 * for which we have failed in acquiring an IP address from DHCP. A value of
364 * N means that we will make N+1 connection attempts in all.
366 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
367 * value if a Settings value is not present.
369 private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
371 /* Tracks if suspend optimizations need to be disabled by DHCP,
372 * screen or due to high perf mode.
373 * When any of them needs to disable it, we keep the suspend optimizations
376 private int mSuspendOptNeedsDisabled = 0;
378 private static final int SUSPEND_DUE_TO_DHCP = 1;
379 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1;
380 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2;
382 /* Tracks if user has enabled suspend optimizations through settings */
383 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
386 * Default framework scan interval in milliseconds. This is used in the scenario in which
387 * wifi chipset does not support background scanning to set up a
388 * periodic wake up scan so that the device can connect to a new access
389 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
392 private final int mDefaultFrameworkScanIntervalMs;
395 * Supplicant scan interval in milliseconds.
396 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
397 * from the default config if the setting is not set
399 private long mSupplicantScanIntervalMs;
402 * Minimum time interval between enabling all networks.
403 * A device can end up repeatedly connecting to a bad network on screen on/off toggle
404 * due to enabling every time. We add a threshold to avoid this.
406 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
407 private long mLastEnableAllNetworksTime;
410 * Starting and shutting down driver too quick causes problems leading to driver
411 * being in a bad state. Delay driver stop.
413 private final int mDriverStopDelayMs;
414 private int mDelayedStopCounter;
415 private boolean mInDelayedStop = false;
417 // sometimes telephony gives us this data before boot is complete and we can't store it
418 // until after, so the write is deferred
419 private volatile String mPersistedCountryCode;
421 private static final int MIN_RSSI = -200;
422 private static final int MAX_RSSI = 256;
424 /* Default parent state */
425 private State mDefaultState = new DefaultState();
426 /* Temporary initial state */
427 private State mInitialState = new InitialState();
428 /* Driver loaded, waiting for supplicant to start */
429 private State mSupplicantStartingState = new SupplicantStartingState();
430 /* Driver loaded and supplicant ready */
431 private State mSupplicantStartedState = new SupplicantStartedState();
432 /* Waiting for supplicant to stop and monitor to exit */
433 private State mSupplicantStoppingState = new SupplicantStoppingState();
434 /* Driver start issued, waiting for completed event */
435 private State mDriverStartingState = new DriverStartingState();
437 private State mDriverStartedState = new DriverStartedState();
438 /* Wait until p2p is disabled
439 * This is a special state which is entered right after we exit out of DriverStartedState
440 * before transitioning to another state.
442 private State mWaitForP2pDisableState = new WaitForP2pDisableState();
443 /* Driver stopping */
444 private State mDriverStoppingState = new DriverStoppingState();
446 private State mDriverStoppedState = new DriverStoppedState();
447 /* Scan for networks, no connection will be established */
448 private State mScanModeState = new ScanModeState();
449 /* Connecting to an access point */
450 private State mConnectModeState = new ConnectModeState();
451 /* Connected at 802.11 (L2) level */
452 private State mL2ConnectedState = new L2ConnectedState();
453 /* fetching IP after connection to access point (assoc+auth complete) */
454 private State mObtainingIpState = new ObtainingIpState();
455 /* Waiting for link quality verification to be complete */
456 private State mVerifyingLinkState = new VerifyingLinkState();
457 /* Waiting for captive portal check to be complete */
458 private State mCaptivePortalCheckState = new CaptivePortalCheckState();
459 /* Connected with IP addr */
460 private State mConnectedState = new ConnectedState();
461 /* disconnect issued, waiting for network disconnect confirmation */
462 private State mDisconnectingState = new DisconnectingState();
463 /* Network is not connected, supplicant assoc+auth is not complete */
464 private State mDisconnectedState = new DisconnectedState();
465 /* Waiting for WPS to be completed*/
466 private State mWpsRunningState = new WpsRunningState();
468 /* Soft ap is starting up */
469 private State mSoftApStartingState = new SoftApStartingState();
470 /* Soft ap is running */
471 private State mSoftApStartedState = new SoftApStartedState();
472 /* Soft ap is running and we are waiting for tether notification */
473 private State mTetheringState = new TetheringState();
474 /* Soft ap is running and we are tethered through connectivity service */
475 private State mTetheredState = new TetheredState();
476 /* Waiting for untether confirmation before stopping soft Ap */
477 private State mUntetheringState = new UntetheringState();
479 private class TetherStateChange {
480 ArrayList<String> available;
481 ArrayList<String> active;
482 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
490 * One of {@link WifiManager#WIFI_STATE_DISABLED},
491 * {@link WifiManager#WIFI_STATE_DISABLING},
492 * {@link WifiManager#WIFI_STATE_ENABLED},
493 * {@link WifiManager#WIFI_STATE_ENABLING},
494 * {@link WifiManager#WIFI_STATE_UNKNOWN}
497 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
500 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
501 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
502 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
503 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
504 * {@link WifiManager#WIFI_AP_STATE_FAILED}
507 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
509 private static final int SCAN_REQUEST = 0;
510 private static final String ACTION_START_SCAN =
511 "com.android.server.WifiManager.action.START_SCAN";
513 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
514 private static final int DRIVER_STOP_REQUEST = 0;
515 private static final String ACTION_DELAYED_DRIVER_STOP =
516 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
519 * Keep track of whether WIFI is running.
521 private boolean mIsRunning = false;
524 * Keep track of whether we last told the battery stats we had started.
526 private boolean mReportedRunning = false;
529 * Most recently set source of starting WIFI.
531 private final WorkSource mRunningWifiUids = new WorkSource();
534 * The last reported UIDs that were responsible for starting WIFI.
536 private final WorkSource mLastRunningWifiUids = new WorkSource();
538 private final IBatteryStats mBatteryStats;
540 public WifiStateMachine(Context context, String wlanInterface) {
541 super("WifiStateMachine");
544 mInterfaceName = wlanInterface;
546 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
547 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
549 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
550 mNwService = INetworkManagementService.Stub.asInterface(b);
552 mP2pSupported = mContext.getPackageManager().hasSystemFeature(
553 PackageManager.FEATURE_WIFI_DIRECT);
555 mWifiNative = new WifiNative(mInterfaceName);
556 mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
557 mWifiMonitor = new WifiMonitor(this, mWifiNative);
558 mWifiInfo = new WifiInfo();
559 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
561 mLinkProperties = new LinkProperties();
563 mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
565 mNetworkInfo.setIsAvailable(false);
566 mLinkProperties.clear();
568 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
569 mLastSignalLevel = -1;
571 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
572 Intent scanIntent = new Intent(ACTION_START_SCAN, null);
573 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
575 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
576 R.integer.config_wifi_framework_scan_interval);
578 mDriverStopDelayMs = mContext.getResources().getInteger(
579 R.integer.config_wifi_driver_stop_delay);
581 mBackgroundScanSupported = mContext.getResources().getBoolean(
582 R.bool.config_wifi_background_scan_support);
584 mPrimaryDeviceType = mContext.getResources().getString(
585 R.string.config_wifi_p2p_device_type);
587 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
588 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
590 mContext.registerReceiver(
591 new BroadcastReceiver() {
593 public void onReceive(Context context, Intent intent) {
594 ArrayList<String> available = intent.getStringArrayListExtra(
595 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
596 ArrayList<String> active = intent.getStringArrayListExtra(
597 ConnectivityManager.EXTRA_ACTIVE_TETHER);
598 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
600 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
602 mContext.registerReceiver(
603 new BroadcastReceiver() {
605 public void onReceive(Context context, Intent intent) {
606 startScan(UNKNOWN_SCAN_SOURCE);
609 new IntentFilter(ACTION_START_SCAN));
611 IntentFilter screenFilter = new IntentFilter();
612 screenFilter.addAction(Intent.ACTION_SCREEN_ON);
613 screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
614 BroadcastReceiver screenReceiver = new BroadcastReceiver() {
616 public void onReceive(Context context, Intent intent) {
617 String action = intent.getAction();
619 if (action.equals(Intent.ACTION_SCREEN_ON)) {
620 handleScreenStateChanged(true);
621 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
622 handleScreenStateChanged(false);
626 mContext.registerReceiver(screenReceiver, screenFilter);
628 mContext.registerReceiver(
629 new BroadcastReceiver() {
631 public void onReceive(Context context, Intent intent) {
632 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
633 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
636 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
638 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
639 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
640 new ContentObserver(getHandler()) {
642 public void onChange(boolean selfChange) {
643 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
644 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
648 mContext.registerReceiver(
649 new BroadcastReceiver() {
651 public void onReceive(Context context, Intent intent) {
652 sendMessage(CMD_BOOT_COMPLETED);
655 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
657 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
659 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
660 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
662 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
663 mSuspendWakeLock.setReferenceCounted(false);
665 addState(mDefaultState);
666 addState(mInitialState, mDefaultState);
667 addState(mSupplicantStartingState, mDefaultState);
668 addState(mSupplicantStartedState, mDefaultState);
669 addState(mDriverStartingState, mSupplicantStartedState);
670 addState(mDriverStartedState, mSupplicantStartedState);
671 addState(mScanModeState, mDriverStartedState);
672 addState(mConnectModeState, mDriverStartedState);
673 addState(mL2ConnectedState, mConnectModeState);
674 addState(mObtainingIpState, mL2ConnectedState);
675 addState(mVerifyingLinkState, mL2ConnectedState);
676 addState(mCaptivePortalCheckState, mL2ConnectedState);
677 addState(mConnectedState, mL2ConnectedState);
678 addState(mDisconnectingState, mConnectModeState);
679 addState(mDisconnectedState, mConnectModeState);
680 addState(mWpsRunningState, mConnectModeState);
681 addState(mWaitForP2pDisableState, mSupplicantStartedState);
682 addState(mDriverStoppingState, mSupplicantStartedState);
683 addState(mDriverStoppedState, mSupplicantStartedState);
684 addState(mSupplicantStoppingState, mDefaultState);
685 addState(mSoftApStartingState, mDefaultState);
686 addState(mSoftApStartedState, mDefaultState);
687 addState(mTetheringState, mSoftApStartedState);
688 addState(mTetheredState, mSoftApStartedState);
689 addState(mUntetheringState, mSoftApStartedState);
691 setInitialState(mInitialState);
694 setLogOnlyTransitions(false);
695 if (DBG) setDbg(true);
697 //start the state machine
700 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
701 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
702 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
703 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
706 /*********************************************************
707 * Methods exposed for public use
708 ********************************************************/
710 public Messenger getMessenger() {
711 return new Messenger(getHandler());
716 public boolean syncPingSupplicant(AsyncChannel channel) {
717 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
718 boolean result = (resultMsg.arg1 != FAILURE);
726 public void startScan(int callingUid) {
727 sendMessage(CMD_START_SCAN, callingUid);
730 private void noteScanStart(int callingUid) {
731 if (mScanWorkSource == null && callingUid != UNKNOWN_SCAN_SOURCE) {
732 mScanWorkSource = new WorkSource(callingUid);
734 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource);
735 } catch (RemoteException e) {
741 private void noteScanEnd() {
742 if (mScanWorkSource != null) {
744 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
745 } catch (RemoteException e) {
748 mScanWorkSource = null;
753 private void startScanNative(int type) {
754 mWifiNative.scan(type);
755 mScanResultIsPending = true;
761 public void setSupplicantRunning(boolean enable) {
763 sendMessage(CMD_START_SUPPLICANT);
765 sendMessage(CMD_STOP_SUPPLICANT);
772 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
774 sendMessage(CMD_START_AP, wifiConfig);
776 sendMessage(CMD_STOP_AP);
780 public void setWifiApConfiguration(WifiConfiguration config) {
781 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
784 public WifiConfiguration syncGetWifiApConfiguration() {
785 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
786 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
794 public int syncGetWifiState() {
795 return mWifiState.get();
801 public String syncGetWifiStateByName() {
802 switch (mWifiState.get()) {
803 case WIFI_STATE_DISABLING:
805 case WIFI_STATE_DISABLED:
807 case WIFI_STATE_ENABLING:
809 case WIFI_STATE_ENABLED:
811 case WIFI_STATE_UNKNOWN:
812 return "unknown state";
814 return "[invalid state]";
821 public int syncGetWifiApState() {
822 return mWifiApState.get();
828 public String syncGetWifiApStateByName() {
829 switch (mWifiApState.get()) {
830 case WIFI_AP_STATE_DISABLING:
832 case WIFI_AP_STATE_DISABLED:
834 case WIFI_AP_STATE_ENABLING:
836 case WIFI_AP_STATE_ENABLED:
838 case WIFI_AP_STATE_FAILED:
841 return "[invalid state]";
846 * Get status information for the current connection, if any.
847 * @return a {@link WifiInfo} object containing information about the current connection
850 public WifiInfo syncRequestConnectionInfo() {
854 public DhcpResults syncGetDhcpResults() {
855 synchronized (mDhcpResultsLock) {
856 return new DhcpResults(mDhcpResults);
863 public void setDriverStart(boolean enable) {
865 sendMessage(CMD_START_DRIVER);
867 sendMessage(CMD_STOP_DRIVER);
871 public void captivePortalCheckComplete() {
872 sendMessage(CMD_CAPTIVE_CHECK_COMPLETE);
878 public void setOperationalMode(int mode) {
879 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
885 public List<ScanResult> syncGetScanResultsList() {
886 synchronized (mScanResultCache) {
887 List<ScanResult> scanList = new ArrayList<ScanResult>();
888 for(ScanResult result: mScanResults) {
889 scanList.add(new ScanResult(result));
896 * Disconnect from Access Point
898 public void disconnectCommand() {
899 sendMessage(CMD_DISCONNECT);
903 * Initiate a reconnection to AP
905 public void reconnectCommand() {
906 sendMessage(CMD_RECONNECT);
910 * Initiate a re-association to AP
912 public void reassociateCommand() {
913 sendMessage(CMD_REASSOCIATE);
917 * Add a network synchronously
919 * @return network id of the new network
921 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
922 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
923 int result = resultMsg.arg1;
928 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) {
929 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS);
930 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
938 * @param networkId id of the network to be removed
940 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
941 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
942 boolean result = (resultMsg.arg1 != FAILURE);
950 * @param netId network id of the network
951 * @param disableOthers true, if all other networks have to be disabled
952 * @return {@code true} if the operation succeeds, {@code false} otherwise
954 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
955 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
956 disableOthers ? 1 : 0);
957 boolean result = (resultMsg.arg1 != FAILURE);
965 * @param netId network id of the network
966 * @return {@code true} if the operation succeeds, {@code false} otherwise
968 public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
969 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
970 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
976 * Blacklist a BSSID. This will avoid the AP if there are
977 * alternate APs to connect
979 * @param bssid BSSID of the network
981 public void addToBlacklist(String bssid) {
982 sendMessage(CMD_BLACKLIST_NETWORK, bssid);
986 * Clear the blacklist list
989 public void clearBlacklist() {
990 sendMessage(CMD_CLEAR_BLACKLIST);
993 public void enableRssiPolling(boolean enabled) {
994 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
997 public void enableBackgroundScanCommand(boolean enabled) {
998 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0);
1001 public void enableAllNetworks() {
1002 sendMessage(CMD_ENABLE_ALL_NETWORKS);
1006 * Start filtering Multicast v4 packets
1008 public void startFilteringMulticastV4Packets() {
1009 mFilteringMulticastV4Packets.set(true);
1010 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
1014 * Stop filtering Multicast v4 packets
1016 public void stopFilteringMulticastV4Packets() {
1017 mFilteringMulticastV4Packets.set(false);
1018 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
1022 * Start filtering Multicast v4 packets
1024 public void startFilteringMulticastV6Packets() {
1025 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
1029 * Stop filtering Multicast v4 packets
1031 public void stopFilteringMulticastV6Packets() {
1032 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
1036 * Set high performance mode of operation.
1037 * Enabling would set active power mode and disable suspend optimizations;
1038 * disabling would set auto power mode and enable suspend optimizations
1039 * @param enable true if enable, false otherwise
1041 public void setHighPerfModeEnabled(boolean enable) {
1042 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
1046 * Set the country code
1047 * @param countryCode following ISO 3166 format
1048 * @param persist {@code true} if the setting should be remembered.
1050 public void setCountryCode(String countryCode, boolean persist) {
1052 mPersistedCountryCode = countryCode;
1053 Settings.Global.putString(mContext.getContentResolver(),
1054 Settings.Global.WIFI_COUNTRY_CODE,
1057 sendMessage(CMD_SET_COUNTRY_CODE, countryCode);
1061 * Set the operational frequency band
1063 * @param persist {@code true} if the setting should be remembered.
1065 public void setFrequencyBand(int band, boolean persist) {
1067 Settings.Global.putInt(mContext.getContentResolver(),
1068 Settings.Global.WIFI_FREQUENCY_BAND,
1071 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
1075 * Returns the operational frequency band
1077 public int getFrequencyBand() {
1078 return mFrequencyBand.get();
1082 * Returns the wifi configuration file
1084 public String getConfigFile() {
1085 return mWifiConfigStore.getConfigFile();
1089 * Send a message indicating bluetooth adapter connection state changed
1091 public void sendBluetoothAdapterStateChange(int state) {
1092 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
1096 * Save configuration on supplicant
1098 * @return {@code true} if the operation succeeds, {@code false} otherwise
1100 * TODO: deprecate this
1102 public boolean syncSaveConfig(AsyncChannel channel) {
1103 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
1104 boolean result = (resultMsg.arg1 != FAILURE);
1105 resultMsg.recycle();
1109 public void updateBatteryWorkSource(WorkSource newSource) {
1110 synchronized (mRunningWifiUids) {
1112 if (newSource != null) {
1113 mRunningWifiUids.set(newSource);
1116 if (mReportedRunning) {
1117 // If the work source has changed since last time, need
1118 // to remove old work from battery stats.
1119 if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
1120 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
1122 mLastRunningWifiUids.set(mRunningWifiUids);
1125 // Now being started, report it.
1126 mBatteryStats.noteWifiRunning(mRunningWifiUids);
1127 mLastRunningWifiUids.set(mRunningWifiUids);
1128 mReportedRunning = true;
1131 if (mReportedRunning) {
1132 // Last reported we were running, time to stop.
1133 mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
1134 mLastRunningWifiUids.clear();
1135 mReportedRunning = false;
1138 mWakeLock.setWorkSource(newSource);
1139 } catch (RemoteException ignore) {
1145 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1146 super.dump(fd, pw, args);
1147 mSupplicantStateTracker.dump(fd, pw, args);
1148 pw.println("mLinkProperties " + mLinkProperties);
1149 pw.println("mWifiInfo " + mWifiInfo);
1150 pw.println("mDhcpResults " + mDhcpResults);
1151 pw.println("mNetworkInfo " + mNetworkInfo);
1152 pw.println("mLastSignalLevel " + mLastSignalLevel);
1153 pw.println("mLastBssid " + mLastBssid);
1154 pw.println("mLastNetworkId " + mLastNetworkId);
1155 pw.println("mReconnectCount " + mReconnectCount);
1156 pw.println("mOperationalMode " + mOperationalMode);
1157 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
1158 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
1159 pw.println("Supplicant status " + mWifiNative.status());
1160 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan);
1162 mWifiConfigStore.dump(fd, pw, args);
1165 /*********************************************************
1166 * Internal private functions
1167 ********************************************************/
1169 private void handleScreenStateChanged(boolean screenOn) {
1170 if (DBG) log("handleScreenStateChanged: " + screenOn);
1171 enableRssiPolling(screenOn);
1172 if (mBackgroundScanSupported) {
1173 enableBackgroundScanCommand(screenOn == false);
1176 if (screenOn) enableAllNetworks();
1177 if (mUserWantsSuspendOpt.get()) {
1179 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
1181 //Allow 2s for suspend optimizations to be set
1182 mSuspendWakeLock.acquire(2000);
1183 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
1186 mScreenBroadcastReceived.set(true);
1189 private void checkAndSetConnectivityInstance() {
1191 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1195 private boolean startTethering(ArrayList<String> available) {
1197 boolean wifiAvailable = false;
1199 checkAndSetConnectivityInstance();
1201 String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1203 for (String intf : available) {
1204 for (String regex : wifiRegexs) {
1205 if (intf.matches(regex)) {
1207 InterfaceConfiguration ifcg = null;
1209 ifcg = mNwService.getInterfaceConfig(intf);
1211 /* IP/netmask: 192.168.43.1/255.255.255.0 */
1212 ifcg.setLinkAddress(new LinkAddress(
1213 NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
1214 ifcg.setInterfaceUp();
1216 mNwService.setInterfaceConfig(intf, ifcg);
1218 } catch (Exception e) {
1219 loge("Error configuring interface " + intf + ", :" + e);
1223 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1224 loge("Error tethering on " + intf);
1227 mTetherInterfaceName = intf;
1232 // We found no interfaces to tether
1236 private void stopTethering() {
1238 checkAndSetConnectivityInstance();
1240 /* Clear the interface config to allow dhcp correctly configure new
1242 InterfaceConfiguration ifcg = null;
1244 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
1246 ifcg.setLinkAddress(
1247 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
1248 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
1250 } catch (Exception e) {
1251 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
1254 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1255 loge("Untether initiate failed!");
1259 private boolean isWifiTethered(ArrayList<String> active) {
1261 checkAndSetConnectivityInstance();
1263 String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1264 for (String intf : active) {
1265 for (String regex : wifiRegexs) {
1266 if (intf.matches(regex)) {
1271 // We found no interfaces that are tethered
1276 * Set the country code from the system setting value, if any.
1278 private void setCountryCode() {
1279 String countryCode = Settings.Global.getString(mContext.getContentResolver(),
1280 Settings.Global.WIFI_COUNTRY_CODE);
1281 if (countryCode != null && !countryCode.isEmpty()) {
1282 setCountryCode(countryCode, false);
1284 //use driver default
1289 * Set the frequency band from the system setting value, if any.
1291 private void setFrequencyBand() {
1292 int band = Settings.Global.getInt(mContext.getContentResolver(),
1293 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1294 setFrequencyBand(band, false);
1297 private void setSuspendOptimizationsNative(int reason, boolean enabled) {
1298 if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled);
1300 mSuspendOptNeedsDisabled &= ~reason;
1301 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
1302 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
1303 mWifiNative.setSuspendOptimizations(true);
1306 mSuspendOptNeedsDisabled |= reason;
1307 mWifiNative.setSuspendOptimizations(false);
1311 private void setSuspendOptimizations(int reason, boolean enabled) {
1312 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
1314 mSuspendOptNeedsDisabled &= ~reason;
1316 mSuspendOptNeedsDisabled |= reason;
1318 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
1321 private void setWifiState(int wifiState) {
1322 final int previousWifiState = mWifiState.get();
1325 if (wifiState == WIFI_STATE_ENABLED) {
1326 mBatteryStats.noteWifiOn();
1327 } else if (wifiState == WIFI_STATE_DISABLED) {
1328 mBatteryStats.noteWifiOff();
1330 } catch (RemoteException e) {
1331 loge("Failed to note battery stats in wifi");
1334 mWifiState.set(wifiState);
1336 if (DBG) log("setWifiState: " + syncGetWifiStateByName());
1338 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1339 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1340 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1341 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1342 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1345 private void setWifiApState(int wifiApState) {
1346 final int previousWifiApState = mWifiApState.get();
1349 if (wifiApState == WIFI_AP_STATE_ENABLED) {
1350 mBatteryStats.noteWifiOn();
1351 } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1352 mBatteryStats.noteWifiOff();
1354 } catch (RemoteException e) {
1355 loge("Failed to note battery stats in wifi");
1359 mWifiApState.set(wifiApState);
1361 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
1363 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1364 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1365 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1366 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1367 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1370 private static final String ID_STR = "id=";
1371 private static final String BSSID_STR = "bssid=";
1372 private static final String FREQ_STR = "freq=";
1373 private static final String LEVEL_STR = "level=";
1374 private static final String TSF_STR = "tsf=";
1375 private static final String FLAGS_STR = "flags=";
1376 private static final String SSID_STR = "ssid=";
1377 private static final String DELIMITER_STR = "====";
1378 private static final String END_STR = "####";
1384 * bssid=68:7f:76:d7:1a:6e
1387 * tsf=1344626243700342
1388 * flags=[WPA2-PSK-CCMP][WPS][ESS]
1392 * bssid=68:5f:74:d7:1a:6f
1395 * tsf=1344626243700373
1396 * flags=[WPA2-PSK-CCMP][WPS][ESS]
1400 private void setScanResults() {
1406 WifiSsid wifiSsid = null;
1409 StringBuffer scanResultsBuf = new StringBuffer();
1413 tmpResults = mWifiNative.scanResults(sid);
1414 if (TextUtils.isEmpty(tmpResults)) break;
1415 scanResultsBuf.append(tmpResults);
1416 scanResultsBuf.append("\n");
1417 String[] lines = tmpResults.split("\n");
1419 for (int i=lines.length - 1; i >= 0; i--) {
1420 if (lines[i].startsWith(END_STR)) {
1422 } else if (lines[i].startsWith(ID_STR)) {
1424 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
1425 } catch (NumberFormatException e) {
1431 if (sid == -1) break;
1434 scanResults = scanResultsBuf.toString();
1435 if (TextUtils.isEmpty(scanResults)) {
1439 synchronized(mScanResultCache) {
1440 mScanResults = new ArrayList<ScanResult>();
1441 String[] lines = scanResults.split("\n");
1443 for (String line : lines) {
1444 if (line.startsWith(BSSID_STR)) {
1445 bssid = line.substring(BSSID_STR.length());
1446 } else if (line.startsWith(FREQ_STR)) {
1448 freq = Integer.parseInt(line.substring(FREQ_STR.length()));
1449 } catch (NumberFormatException e) {
1452 } else if (line.startsWith(LEVEL_STR)) {
1454 level = Integer.parseInt(line.substring(LEVEL_STR.length()));
1455 /* some implementations avoid negative values by adding 256
1456 * so we need to adjust for that here.
1458 if (level > 0) level -= 256;
1459 } catch(NumberFormatException e) {
1462 } else if (line.startsWith(TSF_STR)) {
1464 tsf = Long.parseLong(line.substring(TSF_STR.length()));
1465 } catch (NumberFormatException e) {
1468 } else if (line.startsWith(FLAGS_STR)) {
1469 flags = line.substring(FLAGS_STR.length());
1470 } else if (line.startsWith(SSID_STR)) {
1471 wifiSsid = WifiSsid.createFromAsciiEncoded(
1472 line.substring(SSID_STR.length()));
1473 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
1474 if (bssid != null) {
1475 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
1476 String key = bssid + ssid;
1477 ScanResult scanResult = mScanResultCache.get(key);
1478 if (scanResult != null) {
1479 scanResult.level = level;
1480 scanResult.wifiSsid = wifiSsid;
1481 // Keep existing API
1482 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() :
1484 scanResult.capabilities = flags;
1485 scanResult.frequency = freq;
1486 scanResult.timestamp = tsf;
1490 wifiSsid, bssid, flags, level, freq, tsf);
1491 mScanResultCache.put(key, scanResult);
1493 mScanResults.add(scanResult);
1507 * Fetch RSSI and linkspeed on current connection
1509 private void fetchRssiAndLinkSpeedNative() {
1511 int newLinkSpeed = -1;
1513 String signalPoll = mWifiNative.signalPoll();
1515 if (signalPoll != null) {
1516 String[] lines = signalPoll.split("\n");
1517 for (String line : lines) {
1518 String[] prop = line.split("=");
1519 if (prop.length < 2) continue;
1521 if (prop[0].equals("RSSI")) {
1522 newRssi = Integer.parseInt(prop[1]);
1523 } else if (prop[0].equals("LINKSPEED")) {
1524 newLinkSpeed = Integer.parseInt(prop[1]);
1526 } catch (NumberFormatException e) {
1527 //Ignore, defaults on rssi and linkspeed are assigned
1532 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1533 /* some implementations avoid negative values by adding 256
1534 * so we need to adjust for that here.
1536 if (newRssi > 0) newRssi -= 256;
1537 mWifiInfo.setRssi(newRssi);
1539 * Rather then sending the raw RSSI out every time it
1540 * changes, we precalculate the signal level that would
1541 * be displayed in the status bar, and only send the
1542 * broadcast if that much more coarse-grained number
1543 * changes. This cuts down greatly on the number of
1544 * broadcasts, at the cost of not informing others
1545 * interested in RSSI of all the changes in signal
1548 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
1549 if (newSignalLevel != mLastSignalLevel) {
1550 sendRssiChangeBroadcast(newRssi);
1552 mLastSignalLevel = newSignalLevel;
1554 mWifiInfo.setRssi(MIN_RSSI);
1557 if (newLinkSpeed != -1) {
1558 mWifiInfo.setLinkSpeed(newLinkSpeed);
1563 * Fetch TX packet counters on current connection
1565 private void fetchPktcntNative(RssiPacketCountInfo info) {
1566 String pktcntPoll = mWifiNative.pktcntPoll();
1568 if (pktcntPoll != null) {
1569 String[] lines = pktcntPoll.split("\n");
1570 for (String line : lines) {
1571 String[] prop = line.split("=");
1572 if (prop.length < 2) continue;
1574 if (prop[0].equals("TXGOOD")) {
1575 info.txgood = Integer.parseInt(prop[1]);
1576 } else if (prop[0].equals("TXBAD")) {
1577 info.txbad = Integer.parseInt(prop[1]);
1579 } catch (NumberFormatException e) {
1586 private void configureLinkProperties() {
1587 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1588 mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId);
1590 synchronized (mDhcpResultsLock) {
1591 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) {
1592 mLinkProperties = mDhcpResults.linkProperties;
1595 mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1597 mLinkProperties.setInterfaceName(mInterfaceName);
1598 if (DBG) log("netId=" + mLastNetworkId + " Link configured: " + mLinkProperties);
1601 private int getMaxDhcpRetries() {
1602 return Settings.Global.getInt(mContext.getContentResolver(),
1603 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
1604 DEFAULT_MAX_DHCP_RETRIES);
1607 private void sendScanResultsAvailableBroadcast() {
1609 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1610 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1611 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1614 private void sendRssiChangeBroadcast(final int newRssi) {
1615 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1616 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1617 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1618 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1621 private void sendNetworkStateChangeBroadcast(String bssid) {
1622 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1623 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1624 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
1625 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1627 intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1628 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
1629 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
1630 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
1632 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1635 private void sendLinkConfigurationChangedBroadcast() {
1636 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1637 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1638 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1639 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1642 private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1643 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1644 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1645 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1646 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1650 * Record the detailed state of a network.
1651 * @param state the new {@code DetailedState}
1653 private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1655 log("setDetailed state, old ="
1656 + mNetworkInfo.getDetailedState() + " and new state=" + state);
1659 if (state != mNetworkInfo.getDetailedState()) {
1660 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
1664 private DetailedState getNetworkDetailedState() {
1665 return mNetworkInfo.getDetailedState();
1669 private SupplicantState handleSupplicantStateChange(Message message) {
1670 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
1671 SupplicantState state = stateChangeResult.state;
1672 // Supplicant state change
1673 // [31-13] Reserved for future use
1674 // [8 - 0] Supplicant state (as defined in SupplicantState.java)
1675 // 50023 supplicant_state_changed (custom|1|5)
1676 mWifiInfo.setSupplicantState(state);
1677 // Network id is only valid when we start connecting
1678 if (SupplicantState.isConnecting(state)) {
1679 mWifiInfo.setNetworkId(stateChangeResult.networkId);
1681 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1684 mWifiInfo.setBSSID(stateChangeResult.BSSID);
1685 mWifiInfo.setSSID(stateChangeResult.wifiSsid);
1687 mSupplicantStateTracker.sendMessage(Message.obtain(message));
1693 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1694 * using the interface, stopping DHCP & disabling interface
1696 private void handleNetworkDisconnect() {
1697 if (DBG) log("Stopping DHCP and clearing IP");
1702 mNwService.clearInterfaceAddresses(mInterfaceName);
1703 mNwService.disableIpv6(mInterfaceName);
1704 } catch (Exception e) {
1705 loge("Failed to clear addresses or disable ipv6" + e);
1708 /* Reset data structures */
1709 mWifiInfo.setInetAddress(null);
1710 mWifiInfo.setBSSID(null);
1711 mWifiInfo.setSSID(null);
1712 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1713 mWifiInfo.setRssi(MIN_RSSI);
1714 mWifiInfo.setLinkSpeed(-1);
1715 mWifiInfo.setMeteredHint(false);
1717 setNetworkDetailedState(DetailedState.DISCONNECTED);
1718 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
1720 /* Clear network properties */
1721 mLinkProperties.clear();
1723 /* send event to CM & network change broadcast */
1724 sendNetworkStateChangeBroadcast(mLastBssid);
1726 /* Clear IP settings if the network used DHCP */
1727 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1728 mWifiConfigStore.clearLinkProperties(mLastNetworkId);
1732 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1735 private void handleSupplicantConnectionLoss() {
1736 /* Socket connection can be lost when we do a graceful shutdown
1737 * or when the driver is hung. Ensure supplicant is stopped here.
1739 mWifiNative.killSupplicant(mP2pSupported);
1740 mWifiNative.closeSupplicantConnection();
1741 sendSupplicantConnectionChangedBroadcast(false);
1742 setWifiState(WIFI_STATE_DISABLED);
1745 void handlePreDhcpSetup() {
1746 if (!mBluetoothConnectionActive) {
1748 * There are problems setting the Wi-Fi driver's power
1749 * mode to active when bluetooth coexistence mode is
1752 * We set Wi-Fi to active mode when
1753 * obtaining an IP address because we've found
1754 * compatibility issues with some routers with low power
1757 * In order for this active power mode to properly be set,
1758 * we disable coexistence mode until we're done with
1759 * obtaining an IP address. One exception is if we
1760 * are currently connected to a headset, since disabling
1761 * coexistence would interrupt that connection.
1763 // Disable the coexistence mode
1764 mWifiNative.setBluetoothCoexistenceMode(
1765 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1768 /* Disable power save and suspend optimizations during DHCP */
1769 // Note: The order here is important for now. Brcm driver changes
1770 // power settings when we control suspend mode optimizations.
1771 // TODO: Remove this comment when the driver is fixed.
1772 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
1773 mWifiNative.setPowerSave(false);
1778 if (mDhcpStateMachine == null) {
1779 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
1780 mContext, WifiStateMachine.this, mInterfaceName);
1783 mDhcpStateMachine.registerForPreDhcpNotification();
1784 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
1788 if (mDhcpStateMachine != null) {
1789 /* In case we were in middle of DHCP operation restore back powermode */
1790 handlePostDhcpSetup();
1791 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1795 void handlePostDhcpSetup() {
1796 /* Restore power save and suspend optimizations */
1797 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
1798 mWifiNative.setPowerSave(true);
1800 // Set the coexistence mode back to its default value
1801 mWifiNative.setBluetoothCoexistenceMode(
1802 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1805 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
1806 mLastSignalLevel = -1; // force update of signal strength
1807 mReconnectCount = 0; //Reset IP failure tracking
1808 synchronized (mDhcpResultsLock) {
1809 mDhcpResults = dhcpResults;
1811 LinkProperties linkProperties = dhcpResults.linkProperties;
1812 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties));
1813 InetAddress addr = null;
1814 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator();
1815 if (addrs.hasNext()) {
1816 addr = addrs.next();
1818 mWifiInfo.setInetAddress(addr);
1819 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
1820 if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1821 //DHCP renewal in connected state
1822 linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
1823 if (!linkProperties.equals(mLinkProperties)) {
1825 log("Link configuration changed for netId: " + mLastNetworkId
1826 + " old: " + mLinkProperties + "new: " + linkProperties);
1828 mLinkProperties = linkProperties;
1829 sendLinkConfigurationChangedBroadcast();
1832 configureLinkProperties();
1836 private void handleFailedIpConfiguration() {
1837 loge("IP configuration failed");
1839 mWifiInfo.setInetAddress(null);
1840 mWifiInfo.setMeteredHint(false);
1842 * If we've exceeded the maximum number of retries for DHCP
1843 * to a given network, disable the network
1845 int maxRetries = getMaxDhcpRetries();
1846 // maxRetries == 0 means keep trying forever
1847 if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
1849 mReconnectCount + " times, Disabling " + mLastNetworkId);
1850 mWifiConfigStore.disableNetwork(mLastNetworkId,
1851 WifiConfiguration.DISABLED_DHCP_FAILURE);
1852 mReconnectCount = 0;
1855 /* DHCP times out after about 30 seconds, we do a
1856 * disconnect and an immediate reconnect to try again
1858 mWifiNative.disconnect();
1859 mWifiNative.reconnect();
1862 /* Current design is to not set the config on a running hostapd but instead
1863 * stop and start tethering when user changes config on a running access point
1865 * TODO: Add control channel setup through hostapd that allows changing config
1866 * on a running daemon
1868 private void startSoftApWithConfig(final WifiConfiguration config) {
1869 // start hostapd on a seperate thread
1870 new Thread(new Runnable() {
1873 mNwService.startAccessPoint(config, mInterfaceName);
1874 } catch (Exception e) {
1875 loge("Exception in softap start " + e);
1877 mNwService.stopAccessPoint(mInterfaceName);
1878 mNwService.startAccessPoint(config, mInterfaceName);
1879 } catch (Exception e1) {
1880 loge("Exception in softap re-start " + e1);
1881 sendMessage(CMD_START_AP_FAILURE);
1885 if (DBG) log("Soft AP start successful");
1886 sendMessage(CMD_START_AP_SUCCESS);
1891 /********************************************************
1893 *******************************************************/
1895 class DefaultState extends State {
1897 public boolean processMessage(Message message) {
1898 switch (message.what) {
1899 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1900 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1901 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1903 loge("WifiP2pService connection failure, error=" + message.arg1);
1906 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1907 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
1908 //TODO: Re-establish connection to state machine after a delay
1909 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
1911 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1912 mBluetoothConnectionActive = (message.arg1 !=
1913 BluetoothAdapter.STATE_DISCONNECTED);
1915 /* Synchronous call returns */
1916 case CMD_PING_SUPPLICANT:
1917 case CMD_ENABLE_NETWORK:
1918 case CMD_ADD_OR_UPDATE_NETWORK:
1919 case CMD_REMOVE_NETWORK:
1920 case CMD_SAVE_CONFIG:
1921 replyToMessage(message, message.what, FAILURE);
1923 case CMD_GET_CONFIGURED_NETWORKS:
1924 replyToMessage(message, message.what, (List<WifiConfiguration>) null);
1926 case CMD_ENABLE_RSSI_POLL:
1927 mEnableRssiPolling = (message.arg1 == 1);
1929 case CMD_ENABLE_BACKGROUND_SCAN:
1930 mEnableBackgroundScan = (message.arg1 == 1);
1932 case CMD_SET_HIGH_PERF_MODE:
1933 if (message.arg1 == 1) {
1934 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
1936 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
1939 case CMD_BOOT_COMPLETED:
1940 String countryCode = mPersistedCountryCode;
1941 if (TextUtils.isEmpty(countryCode) == false) {
1942 Settings.Global.putString(mContext.getContentResolver(),
1943 Settings.Global.WIFI_COUNTRY_CODE,
1945 // it may be that the state transition that should send this info
1946 // to the driver happened between mPersistedCountryCode getting set
1947 // and now, so simply persisting it here would mean we have sent
1948 // nothing to the driver. Send the cmd so it might be set now.
1949 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode);
1953 case CMD_START_SCAN:
1954 case CMD_START_SUPPLICANT:
1955 case CMD_STOP_SUPPLICANT:
1956 case CMD_STOP_SUPPLICANT_FAILED:
1957 case CMD_START_DRIVER:
1958 case CMD_STOP_DRIVER:
1959 case CMD_DELAYED_STOP_DRIVER:
1960 case CMD_DRIVER_START_TIMED_OUT:
1961 case CMD_CAPTIVE_CHECK_COMPLETE:
1963 case CMD_START_AP_SUCCESS:
1964 case CMD_START_AP_FAILURE:
1966 case CMD_TETHER_STATE_CHANGE:
1967 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
1968 case CMD_DISCONNECT:
1970 case CMD_REASSOCIATE:
1971 case WifiMonitor.SUP_CONNECTION_EVENT:
1972 case WifiMonitor.SUP_DISCONNECTION_EVENT:
1973 case WifiMonitor.NETWORK_CONNECTION_EVENT:
1974 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
1975 case WifiMonitor.SCAN_RESULTS_EVENT:
1976 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
1977 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
1978 case WifiMonitor.WPS_OVERLAP_EVENT:
1979 case CMD_BLACKLIST_NETWORK:
1980 case CMD_CLEAR_BLACKLIST:
1981 case CMD_SET_OPERATIONAL_MODE:
1982 case CMD_SET_COUNTRY_CODE:
1983 case CMD_SET_FREQUENCY_BAND:
1985 case CMD_ENABLE_ALL_NETWORKS:
1986 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1987 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1988 /* Handled by WifiApConfigStore */
1989 case CMD_SET_AP_CONFIG:
1990 case CMD_SET_AP_CONFIG_COMPLETED:
1991 case CMD_REQUEST_AP_CONFIG:
1992 case CMD_RESPONSE_AP_CONFIG:
1993 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
1994 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
1995 case CMD_NO_NETWORKS_PERIODIC_SCAN:
1996 case CMD_DISABLE_P2P_RSP:
1998 case DhcpStateMachine.CMD_ON_QUIT:
1999 mDhcpStateMachine = null;
2001 case CMD_SET_SUSPEND_OPT_ENABLED:
2002 if (message.arg1 == 1) {
2003 mSuspendWakeLock.release();
2004 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
2006 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
2009 case WifiMonitor.DRIVER_HUNG_EVENT:
2010 setSupplicantRunning(false);
2011 setSupplicantRunning(true);
2013 case WifiManager.CONNECT_NETWORK:
2014 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
2017 case WifiManager.FORGET_NETWORK:
2018 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
2021 case WifiManager.SAVE_NETWORK:
2022 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
2025 case WifiManager.START_WPS:
2026 replyToMessage(message, WifiManager.WPS_FAILED,
2029 case WifiManager.CANCEL_WPS:
2030 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
2033 case WifiManager.DISABLE_NETWORK:
2034 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
2037 case WifiManager.RSSI_PKTCNT_FETCH:
2038 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
2041 case WifiP2pService.P2P_CONNECTION_CHANGED:
2042 NetworkInfo info = (NetworkInfo) message.obj;
2043 mP2pConnected.set(info.isConnected());
2045 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
2046 mTemporarilyDisconnectWifi = (message.arg1 == 1);
2047 replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
2050 loge("Error! unhandled message" + message);
2057 class InitialState extends State {
2059 public void enter() {
2060 mWifiNative.unloadDriver();
2062 if (mWifiP2pChannel == null) {
2063 mWifiP2pChannel = new AsyncChannel();
2064 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
2067 if (mWifiApConfigChannel == null) {
2068 mWifiApConfigChannel = new AsyncChannel();
2069 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
2070 mContext, getHandler());
2071 wifiApConfigStore.loadApConfiguration();
2072 mWifiApConfigChannel.connectSync(mContext, getHandler(),
2073 wifiApConfigStore.getMessenger());
2077 public boolean processMessage(Message message) {
2078 switch (message.what) {
2079 case CMD_START_SUPPLICANT:
2080 if (mWifiNative.loadDriver()) {
2082 mNwService.wifiFirmwareReload(mInterfaceName, "STA");
2083 } catch (Exception e) {
2084 loge("Failed to reload STA firmware " + e);
2089 // A runtime crash can leave the interface up and
2090 // this affects connectivity when supplicant starts up.
2091 // Ensure interface is down before a supplicant start.
2092 mNwService.setInterfaceDown(mInterfaceName);
2093 // Set privacy extensions
2094 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
2096 // IPv6 is enabled only as long as access point is connected since:
2097 // - IPv6 addresses and routes stick around after disconnection
2098 // - kernel is unaware when connected and fails to start IPv6 negotiation
2099 // - kernel can start autoconfiguration when 802.1x is not complete
2100 mNwService.disableIpv6(mInterfaceName);
2101 } catch (RemoteException re) {
2102 loge("Unable to change interface settings: " + re);
2103 } catch (IllegalStateException ie) {
2104 loge("Unable to change interface settings: " + ie);
2107 /* Stop a running supplicant after a runtime restart
2108 * Avoids issues with drivers that do not handle interface down
2109 * on a running supplicant properly.
2111 mWifiNative.killSupplicant(mP2pSupported);
2112 if(mWifiNative.startSupplicant(mP2pSupported)) {
2113 setWifiState(WIFI_STATE_ENABLING);
2114 if (DBG) log("Supplicant start successful");
2115 mWifiMonitor.startMonitoring();
2116 transitionTo(mSupplicantStartingState);
2118 loge("Failed to start supplicant!");
2121 loge("Failed to load driver");
2125 if (mWifiNative.loadDriver()) {
2126 setWifiApState(WIFI_AP_STATE_ENABLING);
2127 transitionTo(mSoftApStartingState);
2129 loge("Failed to load driver for softap");
2138 class SupplicantStartingState extends State {
2139 private void initializeWpsDetails() {
2141 detail = SystemProperties.get("ro.product.name", "");
2142 if (!mWifiNative.setDeviceName(detail)) {
2143 loge("Failed to set device name " + detail);
2145 detail = SystemProperties.get("ro.product.manufacturer", "");
2146 if (!mWifiNative.setManufacturer(detail)) {
2147 loge("Failed to set manufacturer " + detail);
2149 detail = SystemProperties.get("ro.product.model", "");
2150 if (!mWifiNative.setModelName(detail)) {
2151 loge("Failed to set model name " + detail);
2153 detail = SystemProperties.get("ro.product.model", "");
2154 if (!mWifiNative.setModelNumber(detail)) {
2155 loge("Failed to set model number " + detail);
2157 detail = SystemProperties.get("ro.serialno", "");
2158 if (!mWifiNative.setSerialNumber(detail)) {
2159 loge("Failed to set serial number " + detail);
2161 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
2162 loge("Failed to set WPS config methods");
2164 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
2165 loge("Failed to set primary device type " + mPrimaryDeviceType);
2170 public boolean processMessage(Message message) {
2171 switch(message.what) {
2172 case WifiMonitor.SUP_CONNECTION_EVENT:
2173 if (DBG) log("Supplicant connection established");
2174 setWifiState(WIFI_STATE_ENABLED);
2175 mSupplicantRestartCount = 0;
2176 /* Reset the supplicant state to indicate the supplicant
2177 * state is not known at this time */
2178 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2179 /* Initialize data structures */
2181 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2182 mLastSignalLevel = -1;
2184 mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
2185 mWifiConfigStore.loadAndEnableAllNetworks();
2186 initializeWpsDetails();
2188 sendSupplicantConnectionChangedBroadcast(true);
2189 transitionTo(mDriverStartedState);
2191 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2192 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2193 loge("Failed to setup control channel, restart supplicant");
2194 mWifiNative.killSupplicant(mP2pSupported);
2195 transitionTo(mInitialState);
2196 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2198 loge("Failed " + mSupplicantRestartCount +
2199 " times to start supplicant, unload driver");
2200 mSupplicantRestartCount = 0;
2201 setWifiState(WIFI_STATE_UNKNOWN);
2202 transitionTo(mInitialState);
2205 case CMD_START_SUPPLICANT:
2206 case CMD_STOP_SUPPLICANT:
2209 case CMD_START_DRIVER:
2210 case CMD_STOP_DRIVER:
2211 case CMD_SET_OPERATIONAL_MODE:
2212 case CMD_SET_COUNTRY_CODE:
2213 case CMD_SET_FREQUENCY_BAND:
2214 case CMD_START_PACKET_FILTERING:
2215 case CMD_STOP_PACKET_FILTERING:
2216 deferMessage(message);
2225 class SupplicantStartedState extends State {
2227 public void enter() {
2228 /* Wifi is available as long as we have a connection to supplicant */
2229 mNetworkInfo.setIsAvailable(true);
2231 int defaultInterval = mContext.getResources().getInteger(
2232 R.integer.config_wifi_supplicant_scan_interval);
2234 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
2235 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2238 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
2241 public boolean processMessage(Message message) {
2242 switch(message.what) {
2243 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
2244 if (mP2pSupported) {
2245 transitionTo(mWaitForP2pDisableState);
2247 transitionTo(mSupplicantStoppingState);
2250 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
2251 loge("Connection lost, restart supplicant");
2252 handleSupplicantConnectionLoss();
2253 handleNetworkDisconnect();
2254 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2255 if (mP2pSupported) {
2256 transitionTo(mWaitForP2pDisableState);
2258 transitionTo(mInitialState);
2260 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2262 case WifiMonitor.SCAN_RESULTS_EVENT:
2264 sendScanResultsAvailableBroadcast();
2265 mScanResultIsPending = false;
2267 case CMD_PING_SUPPLICANT:
2268 boolean ok = mWifiNative.ping();
2269 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2271 /* Cannot start soft AP while in client mode */
2273 loge("Failed to start soft AP with a running supplicant");
2274 setWifiApState(WIFI_AP_STATE_FAILED);
2276 case CMD_SET_OPERATIONAL_MODE:
2277 mOperationalMode = message.arg1;
2286 public void exit() {
2287 mNetworkInfo.setIsAvailable(false);
2291 class SupplicantStoppingState extends State {
2293 public void enter() {
2294 /* Send any reset commands to supplicant before shutting it down */
2295 handleNetworkDisconnect();
2296 if (mDhcpStateMachine != null) {
2297 mDhcpStateMachine.doQuit();
2300 if (DBG) log("stopping supplicant");
2301 if (!mWifiNative.stopSupplicant()) {
2302 loge("Failed to stop supplicant");
2305 /* Send ourselves a delayed message to indicate failure after a wait time */
2306 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
2307 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
2308 setWifiState(WIFI_STATE_DISABLING);
2309 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2312 public boolean processMessage(Message message) {
2313 switch(message.what) {
2314 case WifiMonitor.SUP_CONNECTION_EVENT:
2315 loge("Supplicant connection received while stopping");
2317 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2318 if (DBG) log("Supplicant connection lost");
2319 handleSupplicantConnectionLoss();
2320 transitionTo(mInitialState);
2322 case CMD_STOP_SUPPLICANT_FAILED:
2323 if (message.arg1 == mSupplicantStopFailureToken) {
2324 loge("Timed out on a supplicant stop, kill and proceed");
2325 handleSupplicantConnectionLoss();
2326 transitionTo(mInitialState);
2329 case CMD_START_SUPPLICANT:
2330 case CMD_STOP_SUPPLICANT:
2333 case CMD_START_DRIVER:
2334 case CMD_STOP_DRIVER:
2335 case CMD_SET_OPERATIONAL_MODE:
2336 case CMD_SET_COUNTRY_CODE:
2337 case CMD_SET_FREQUENCY_BAND:
2338 case CMD_START_PACKET_FILTERING:
2339 case CMD_STOP_PACKET_FILTERING:
2340 deferMessage(message);
2349 class DriverStartingState extends State {
2352 public void enter() {
2354 /* Send ourselves a delayed message to start driver a second time */
2355 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2356 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2359 public boolean processMessage(Message message) {
2360 switch(message.what) {
2361 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2362 SupplicantState state = handleSupplicantStateChange(message);
2363 /* If suplicant is exiting out of INTERFACE_DISABLED state into
2364 * a state that indicates driver has started, it is ready to
2365 * receive driver commands
2367 if (SupplicantState.isDriverActive(state)) {
2368 transitionTo(mDriverStartedState);
2371 case CMD_DRIVER_START_TIMED_OUT:
2372 if (message.arg1 == mDriverStartToken) {
2374 loge("Failed to start driver after " + mTries);
2375 transitionTo(mDriverStoppedState);
2377 loge("Driver start failed, retrying");
2378 mWakeLock.acquire();
2379 mWifiNative.startDriver();
2380 mWakeLock.release();
2383 /* Send ourselves a delayed message to start driver again */
2384 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
2385 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
2389 /* Queue driver commands & connection events */
2390 case CMD_START_DRIVER:
2391 case CMD_STOP_DRIVER:
2392 case WifiMonitor.NETWORK_CONNECTION_EVENT:
2393 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2394 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2395 case WifiMonitor.WPS_OVERLAP_EVENT:
2396 case CMD_SET_COUNTRY_CODE:
2397 case CMD_SET_FREQUENCY_BAND:
2398 case CMD_START_PACKET_FILTERING:
2399 case CMD_STOP_PACKET_FILTERING:
2400 case CMD_START_SCAN:
2401 case CMD_DISCONNECT:
2402 case CMD_REASSOCIATE:
2404 deferMessage(message);
2413 class DriverStartedState extends State {
2415 public void enter() {
2417 mInDelayedStop = false;
2418 mDelayedStopCounter++;
2419 updateBatteryWorkSource(null);
2421 * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2422 * When this mode is on, some of the low-level scan parameters used by the
2423 * driver are changed to reduce interference with bluetooth
2425 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2426 /* set country code */
2428 /* set frequency band of operation */
2430 /* initialize network state */
2431 setNetworkDetailedState(DetailedState.DISCONNECTED);
2433 /* Remove any filtering on Multicast v6 at start */
2434 mWifiNative.stopFilteringMulticastV6Packets();
2436 /* Reset Multicast v4 filtering state */
2437 if (mFilteringMulticastV4Packets.get()) {
2438 mWifiNative.startFilteringMulticastV4Packets();
2440 mWifiNative.stopFilteringMulticastV4Packets();
2443 if (mOperationalMode != CONNECT_MODE) {
2444 mWifiNative.disconnect();
2445 transitionTo(mScanModeState);
2447 /* Driver stop may have disabled networks, enable right after start */
2448 mWifiConfigStore.enableAllNetworks();
2449 mWifiNative.reconnect();
2450 // Status pulls in the current supplicant state and network connection state
2451 // events over the monitor connection. This helps framework sync up with
2452 // current supplicant state
2453 mWifiNative.status();
2454 transitionTo(mDisconnectedState);
2457 // We may have missed screen update at boot
2458 if (mScreenBroadcastReceived.get() == false) {
2459 PowerManager powerManager = (PowerManager)mContext.getSystemService(
2460 Context.POWER_SERVICE);
2461 handleScreenStateChanged(powerManager.isScreenOn());
2463 // Set the right suspend mode settings
2464 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
2465 && mUserWantsSuspendOpt.get());
2467 mWifiNative.setPowerSave(true);
2469 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
2471 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
2472 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2473 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
2474 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2478 public boolean processMessage(Message message) {
2479 switch(message.what) {
2480 case CMD_START_SCAN:
2481 noteScanStart(message.arg1);
2482 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
2484 case CMD_SET_COUNTRY_CODE:
2485 String country = (String) message.obj;
2486 if (DBG) log("set country code " + country);
2487 if (!mWifiNative.setCountryCode(country.toUpperCase())) {
2488 loge("Failed to set country code " + country);
2491 case CMD_SET_FREQUENCY_BAND:
2492 int band = message.arg1;
2493 if (DBG) log("set frequency band " + band);
2494 if (mWifiNative.setBand(band)) {
2495 mFrequencyBand.set(band);
2496 //Fetch the latest scan results when frequency band is set
2497 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
2499 loge("Failed to set frequency band " + band);
2502 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2503 mBluetoothConnectionActive = (message.arg1 !=
2504 BluetoothAdapter.STATE_DISCONNECTED);
2505 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
2507 case CMD_STOP_DRIVER:
2508 int mode = message.arg1;
2510 /* Already doing a delayed stop */
2511 if (mInDelayedStop) {
2512 if (DBG) log("Already in delayed stop");
2515 /* disconnect right now, but leave the driver running for a bit */
2516 mWifiConfigStore.disableAllNetworks();
2518 mInDelayedStop = true;
2519 mDelayedStopCounter++;
2520 if (DBG) log("Delayed stop message " + mDelayedStopCounter);
2522 /* send regular delayed shut down */
2523 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
2524 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
2525 mDriverStopIntent = PendingIntent.getBroadcast(mContext,
2526 DRIVER_STOP_REQUEST, driverStopIntent,
2527 PendingIntent.FLAG_UPDATE_CURRENT);
2529 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
2530 + mDriverStopDelayMs, mDriverStopIntent);
2532 case CMD_START_DRIVER:
2533 if (mInDelayedStop) {
2534 mInDelayedStop = false;
2535 mDelayedStopCounter++;
2536 mAlarmManager.cancel(mDriverStopIntent);
2537 if (DBG) log("Delayed stop ignored due to start");
2538 if (mOperationalMode == CONNECT_MODE) {
2539 mWifiConfigStore.enableAllNetworks();
2543 case CMD_DELAYED_STOP_DRIVER:
2544 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
2545 if (message.arg1 != mDelayedStopCounter) break;
2546 if (getCurrentState() != mDisconnectedState) {
2547 mWifiNative.disconnect();
2548 handleNetworkDisconnect();
2550 mWakeLock.acquire();
2551 mWifiNative.stopDriver();
2552 mWakeLock.release();
2553 if (mP2pSupported) {
2554 transitionTo(mWaitForP2pDisableState);
2556 transitionTo(mDriverStoppingState);
2559 case CMD_START_PACKET_FILTERING:
2560 if (message.arg1 == MULTICAST_V6) {
2561 mWifiNative.startFilteringMulticastV6Packets();
2562 } else if (message.arg1 == MULTICAST_V4) {
2563 mWifiNative.startFilteringMulticastV4Packets();
2565 loge("Illegal arugments to CMD_START_PACKET_FILTERING");
2568 case CMD_STOP_PACKET_FILTERING:
2569 if (message.arg1 == MULTICAST_V6) {
2570 mWifiNative.stopFilteringMulticastV6Packets();
2571 } else if (message.arg1 == MULTICAST_V4) {
2572 mWifiNative.stopFilteringMulticastV4Packets();
2574 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
2577 case CMD_SET_SUSPEND_OPT_ENABLED:
2578 if (message.arg1 == 1) {
2579 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
2580 mSuspendWakeLock.release();
2582 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
2585 case CMD_SET_HIGH_PERF_MODE:
2586 if (message.arg1 == 1) {
2587 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
2589 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
2598 public void exit() {
2600 updateBatteryWorkSource(null);
2601 mScanResults = new ArrayList<ScanResult>();
2603 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
2604 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2605 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
2606 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2607 noteScanEnd(); // wrap up any pending request.
2611 class WaitForP2pDisableState extends State {
2612 private State mTransitionToState;
2614 public void enter() {
2615 switch (getCurrentMessage().what) {
2616 case WifiMonitor.SUP_DISCONNECTION_EVENT:
2617 mTransitionToState = mInitialState;
2619 case CMD_DELAYED_STOP_DRIVER:
2620 mTransitionToState = mDriverStoppingState;
2622 case CMD_STOP_SUPPLICANT:
2623 mTransitionToState = mSupplicantStoppingState;
2626 mTransitionToState = mDriverStoppingState;
2629 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
2632 public boolean processMessage(Message message) {
2633 switch(message.what) {
2634 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
2635 transitionTo(mTransitionToState);
2637 /* Defer wifi start/shut and driver commands */
2638 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2639 case CMD_START_SUPPLICANT:
2640 case CMD_STOP_SUPPLICANT:
2643 case CMD_START_DRIVER:
2644 case CMD_STOP_DRIVER:
2645 case CMD_SET_OPERATIONAL_MODE:
2646 case CMD_SET_COUNTRY_CODE:
2647 case CMD_SET_FREQUENCY_BAND:
2648 case CMD_START_PACKET_FILTERING:
2649 case CMD_STOP_PACKET_FILTERING:
2650 case CMD_START_SCAN:
2651 case CMD_DISCONNECT:
2652 case CMD_REASSOCIATE:
2654 deferMessage(message);
2663 class DriverStoppingState extends State {
2665 public boolean processMessage(Message message) {
2666 switch(message.what) {
2667 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2668 SupplicantState state = handleSupplicantStateChange(message);
2669 if (state == SupplicantState.INTERFACE_DISABLED) {
2670 transitionTo(mDriverStoppedState);
2673 /* Queue driver commands */
2674 case CMD_START_DRIVER:
2675 case CMD_STOP_DRIVER:
2676 case CMD_SET_COUNTRY_CODE:
2677 case CMD_SET_FREQUENCY_BAND:
2678 case CMD_START_PACKET_FILTERING:
2679 case CMD_STOP_PACKET_FILTERING:
2680 case CMD_START_SCAN:
2681 case CMD_DISCONNECT:
2682 case CMD_REASSOCIATE:
2684 deferMessage(message);
2693 class DriverStoppedState extends State {
2695 public boolean processMessage(Message message) {
2696 switch (message.what) {
2697 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2698 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
2699 SupplicantState state = stateChangeResult.state;
2700 // A WEXT bug means that we can be back to driver started state
2702 if (SupplicantState.isDriverActive(state)) {
2703 transitionTo(mDriverStartedState);
2706 case CMD_START_DRIVER:
2707 mWakeLock.acquire();
2708 mWifiNative.startDriver();
2709 mWakeLock.release();
2710 transitionTo(mDriverStartingState);
2719 class ScanModeState extends State {
2720 private int mLastOperationMode;
2722 public void enter() {
2723 mWifiConfigStore.disableAllNetworks();
2724 mLastOperationMode = mOperationalMode;
2725 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
2726 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
2727 setWifiState(WIFI_STATE_DISABLED);
2731 public void exit() {
2732 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
2733 setWifiState(WIFI_STATE_ENABLED);
2734 // Load and re-enable networks when going back to enabled state
2735 // This is essential for networks to show up after restore
2736 mWifiConfigStore.loadAndEnableAllNetworks();
2737 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
2739 mWifiConfigStore.enableAllNetworks();
2741 mWifiNative.reconnect();
2744 public boolean processMessage(Message message) {
2745 switch(message.what) {
2746 case CMD_SET_OPERATIONAL_MODE:
2747 if (message.arg1 == CONNECT_MODE) {
2748 mOperationalMode = CONNECT_MODE;
2749 transitionTo(mDisconnectedState);
2755 // Handle scan. All the connection related commands are
2756 // handled only in ConnectModeState
2757 case CMD_START_SCAN:
2758 noteScanStart(message.arg1);
2759 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
2768 class ConnectModeState extends State {
2770 public boolean processMessage(Message message) {
2771 WifiConfiguration config;
2773 switch(message.what) {
2774 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
2775 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
2777 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2778 SupplicantState state = handleSupplicantStateChange(message);
2779 // A driver/firmware hang can now put the interface in a down state.
2780 // We detect the interface going down and recover from it
2781 if (!SupplicantState.isDriverActive(state)) {
2782 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2783 handleNetworkDisconnect();
2785 log("Detected an interface down, restart driver");
2786 transitionTo(mDriverStoppedState);
2787 sendMessage(CMD_START_DRIVER);
2791 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
2792 // when authentication times out after a successful connection,
2793 // we can figure this from the supplicant state. If supplicant
2794 // state is DISCONNECTED, but the mNetworkInfo says we are not
2795 // disconnected, we need to handle a disconnection
2796 if (state == SupplicantState.DISCONNECTED &&
2797 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
2798 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
2799 handleNetworkDisconnect();
2800 transitionTo(mDisconnectedState);
2803 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
2804 if (message.arg1 == 1) {
2805 mWifiNative.disconnect();
2806 mTemporarilyDisconnectWifi = true;
2808 mWifiNative.reconnect();
2809 mTemporarilyDisconnectWifi = false;
2812 case CMD_ADD_OR_UPDATE_NETWORK:
2813 config = (WifiConfiguration) message.obj;
2814 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2815 mWifiConfigStore.addOrUpdateNetwork(config));
2817 case CMD_REMOVE_NETWORK:
2818 ok = mWifiConfigStore.removeNetwork(message.arg1);
2819 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2821 case CMD_ENABLE_NETWORK:
2822 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2823 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2825 case CMD_ENABLE_ALL_NETWORKS:
2826 long time = android.os.SystemClock.elapsedRealtime();
2827 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
2828 mWifiConfigStore.enableAllNetworks();
2829 mLastEnableAllNetworksTime = time;
2832 case WifiManager.DISABLE_NETWORK:
2833 if (mWifiConfigStore.disableNetwork(message.arg1,
2834 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
2835 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
2837 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
2841 case CMD_BLACKLIST_NETWORK:
2842 mWifiNative.addToBlacklist((String)message.obj);
2844 case CMD_CLEAR_BLACKLIST:
2845 mWifiNative.clearBlacklist();
2847 case CMD_SAVE_CONFIG:
2848 ok = mWifiConfigStore.saveConfig();
2849 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2851 // Inform the backup manager about a data change
2852 IBackupManager ibm = IBackupManager.Stub.asInterface(
2853 ServiceManager.getService(Context.BACKUP_SERVICE));
2856 ibm.dataChanged("com.android.providers.settings");
2857 } catch (Exception e) {
2862 case CMD_GET_CONFIGURED_NETWORKS:
2863 replyToMessage(message, message.what,
2864 mWifiConfigStore.getConfiguredNetworks());
2866 /* Do a redundant disconnect without transition */
2867 case CMD_DISCONNECT:
2868 mWifiNative.disconnect();
2871 mWifiNative.reconnect();
2873 case CMD_REASSOCIATE:
2874 mWifiNative.reassociate();
2876 case WifiManager.CONNECT_NETWORK:
2877 /* The connect message can contain a network id passed as arg1 on message or
2878 * or a config passed as obj on message.
2879 * For a new network, a config is passed to create and connect.
2880 * For an existing network, a network id is passed
2882 int netId = message.arg1;
2883 config = (WifiConfiguration) message.obj;
2885 /* Save the network config */
2886 if (config != null) {
2887 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2888 netId = result.getNetworkId();
2891 if (mWifiConfigStore.selectNetwork(netId) &&
2892 mWifiNative.reconnect()) {
2893 /* The state tracker handles enabling networks upon completion/failure */
2894 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
2895 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
2896 /* Expect a disconnection from the old connection */
2897 transitionTo(mDisconnectingState);
2899 loge("Failed to connect config: " + config + " netId: " + netId);
2900 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
2905 case WifiManager.SAVE_NETWORK:
2906 config = (WifiConfiguration) message.obj;
2907 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
2908 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
2909 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
2911 loge("Failed to save network");
2912 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
2916 case WifiManager.FORGET_NETWORK:
2917 if (mWifiConfigStore.forgetNetwork(message.arg1)) {
2918 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
2920 loge("Failed to forget network");
2921 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
2925 case WifiManager.START_WPS:
2926 WpsInfo wpsInfo = (WpsInfo) message.obj;
2927 WpsResult wpsResult;
2928 switch (wpsInfo.setup) {
2930 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
2932 case WpsInfo.KEYPAD:
2933 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
2935 case WpsInfo.DISPLAY:
2936 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
2939 wpsResult = new WpsResult(Status.FAILURE);
2940 loge("Invalid setup for WPS");
2943 if (wpsResult.status == Status.SUCCESS) {
2944 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
2945 transitionTo(mWpsRunningState);
2947 loge("Failed to start WPS with config " + wpsInfo.toString());
2948 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
2951 case WifiMonitor.NETWORK_CONNECTION_EVENT:
2952 if (DBG) log("Network connection established");
2953 mLastNetworkId = message.arg1;
2954 mLastBssid = (String) message.obj;
2956 mWifiInfo.setBSSID(mLastBssid);
2957 mWifiInfo.setNetworkId(mLastNetworkId);
2958 /* send event to CM & network change broadcast */
2959 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
2960 sendNetworkStateChangeBroadcast(mLastBssid);
2961 transitionTo(mObtainingIpState);
2963 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
2964 if (DBG) log("Network connection lost");
2965 handleNetworkDisconnect();
2966 transitionTo(mDisconnectedState);
2975 class L2ConnectedState extends State {
2977 public void enter() {
2979 if (mEnableRssiPolling) {
2980 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
2985 public boolean processMessage(Message message) {
2986 switch (message.what) {
2987 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2988 handlePreDhcpSetup();
2989 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2991 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2992 handlePostDhcpSetup();
2993 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2994 if (DBG) log("DHCP successful");
2995 handleSuccessfulIpConfiguration((DhcpResults) message.obj);
2996 transitionTo(mVerifyingLinkState);
2997 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2998 if (DBG) log("DHCP failed");
2999 handleFailedIpConfiguration();
3000 transitionTo(mDisconnectingState);
3003 case CMD_DISCONNECT:
3004 mWifiNative.disconnect();
3005 transitionTo(mDisconnectingState);
3007 case WifiP2pService.DISCONNECT_WIFI_REQUEST:
3008 if (message.arg1 == 1) {
3009 mWifiNative.disconnect();
3010 mTemporarilyDisconnectWifi = true;
3011 transitionTo(mDisconnectingState);
3014 case CMD_SET_OPERATIONAL_MODE:
3015 if (message.arg1 != CONNECT_MODE) {
3016 sendMessage(CMD_DISCONNECT);
3017 deferMessage(message);
3020 case CMD_START_SCAN:
3021 /* Do not attempt to connect when we are already connected */
3022 noteScanStart(message.arg1);
3023 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
3025 /* Ignore connection to same network */
3026 case WifiManager.CONNECT_NETWORK:
3027 int netId = message.arg1;
3028 if (mWifiInfo.getNetworkId() == netId) {
3032 case WifiManager.SAVE_NETWORK:
3033 WifiConfiguration config = (WifiConfiguration) message.obj;
3034 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
3035 if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
3036 if (result.hasIpChanged()) {
3037 log("Reconfiguring IP on connection");
3038 transitionTo(mObtainingIpState);
3040 if (result.hasProxyChanged()) {
3041 log("Reconfiguring proxy on connection");
3042 configureLinkProperties();
3043 sendLinkConfigurationChangedBroadcast();
3047 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
3048 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
3050 loge("Failed to save network");
3051 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
3056 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3059 if (message.arg1 == mRssiPollToken) {
3060 // Get Info and continue polling
3061 fetchRssiAndLinkSpeedNative();
3062 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3063 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3065 // Polling has completed
3068 case CMD_ENABLE_RSSI_POLL:
3069 mEnableRssiPolling = (message.arg1 == 1);
3071 if (mEnableRssiPolling) {
3073 fetchRssiAndLinkSpeedNative();
3074 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
3075 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
3078 case WifiManager.RSSI_PKTCNT_FETCH:
3079 RssiPacketCountInfo info = new RssiPacketCountInfo();
3080 fetchRssiAndLinkSpeedNative();
3081 info.rssi = mWifiInfo.getRssi();
3082 fetchPktcntNative(info);
3083 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
3093 class ObtainingIpState extends State {
3095 public void enter() {
3096 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
3099 // stop any running dhcp before assigning static IP
3101 DhcpResults dhcpResults = new DhcpResults(
3102 mWifiConfigStore.getLinkProperties(mLastNetworkId));
3103 dhcpResults.linkProperties.setInterfaceName(mInterfaceName);
3104 InterfaceConfiguration ifcg = new InterfaceConfiguration();
3105 Iterator<LinkAddress> addrs =
3106 dhcpResults.linkProperties.getLinkAddresses().iterator();
3107 if (!addrs.hasNext()) {
3108 loge("Static IP lacks address");
3109 sendMessage(CMD_STATIC_IP_FAILURE);
3111 ifcg.setLinkAddress(addrs.next());
3112 ifcg.setInterfaceUp();
3114 mNwService.setInterfaceConfig(mInterfaceName, ifcg);
3115 if (DBG) log("Static IP configuration succeeded");
3116 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
3117 } catch (RemoteException re) {
3118 loge("Static IP configuration failed: " + re);
3119 sendMessage(CMD_STATIC_IP_FAILURE);
3120 } catch (IllegalStateException e) {
3121 loge("Static IP configuration failed: " + e);
3122 sendMessage(CMD_STATIC_IP_FAILURE);
3128 public boolean processMessage(Message message) {
3129 if (DBG) log(getName() + message.toString() + "\n");
3130 switch(message.what) {
3131 case CMD_STATIC_IP_SUCCESS:
3132 handleSuccessfulIpConfiguration((DhcpResults) message.obj);
3133 transitionTo(mVerifyingLinkState);
3135 case CMD_STATIC_IP_FAILURE:
3136 handleFailedIpConfiguration();
3137 transitionTo(mDisconnectingState);
3139 case WifiManager.SAVE_NETWORK:
3140 deferMessage(message);
3142 /* Defer any power mode changes since we must keep active power mode at DHCP */
3143 case CMD_SET_HIGH_PERF_MODE:
3144 deferMessage(message);
3146 /* Defer scan request since we should not switch to other channels at DHCP */
3147 case CMD_START_SCAN:
3148 deferMessage(message);
3157 class VerifyingLinkState extends State {
3159 public void enter() {
3160 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
3161 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
3162 sendNetworkStateChangeBroadcast(mLastBssid);
3165 public boolean processMessage(Message message) {
3166 switch (message.what) {
3167 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3170 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
3171 transitionTo(mCaptivePortalCheckState);
3180 class CaptivePortalCheckState extends State {
3182 public void enter() {
3183 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK);
3184 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK);
3185 sendNetworkStateChangeBroadcast(mLastBssid);
3188 public boolean processMessage(Message message) {
3189 switch (message.what) {
3190 case CMD_CAPTIVE_CHECK_COMPLETE:
3192 mNwService.enableIpv6(mInterfaceName);
3193 } catch (RemoteException re) {
3194 loge("Failed to enable IPv6: " + re);
3195 } catch (IllegalStateException e) {
3196 loge("Failed to enable IPv6: " + e);
3198 setNetworkDetailedState(DetailedState.CONNECTED);
3199 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
3200 sendNetworkStateChangeBroadcast(mLastBssid);
3201 transitionTo(mConnectedState);
3210 class ConnectedState extends State {
3212 public boolean processMessage(Message message) {
3213 switch (message.what) {
3214 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
3215 if (DBG) log("Watchdog reports poor link");
3217 mNwService.disableIpv6(mInterfaceName);
3218 } catch (RemoteException re) {
3219 loge("Failed to disable IPv6: " + re);
3220 } catch (IllegalStateException e) {
3221 loge("Failed to disable IPv6: " + e);
3223 /* Report a disconnect */
3224 setNetworkDetailedState(DetailedState.DISCONNECTED);
3225 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
3226 sendNetworkStateChangeBroadcast(mLastBssid);
3228 transitionTo(mVerifyingLinkState);
3236 public void exit() {
3237 /* Request a CS wakelock during transition to mobile */
3238 checkAndSetConnectivityInstance();
3239 mCm.requestNetworkTransitionWakelock(getName());
3243 class DisconnectingState extends State {
3245 public boolean processMessage(Message message) {
3246 switch (message.what) {
3247 case CMD_SET_OPERATIONAL_MODE:
3248 if (message.arg1 != CONNECT_MODE) {
3249 deferMessage(message);
3252 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3253 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
3254 * we have missed the network disconnection, transition to mDisconnectedState
3255 * and handle the rest of the events there
3257 deferMessage(message);
3258 handleNetworkDisconnect();
3259 transitionTo(mDisconnectedState);
3268 class DisconnectedState extends State {
3269 private boolean mAlarmEnabled = false;
3270 /* This is set from the overlay config file or from a secure setting.
3271 * A value of 0 disables scanning in the framework.
3273 private long mFrameworkScanIntervalMs;
3275 private void setScanAlarm(boolean enabled) {
3276 if (enabled == mAlarmEnabled) return;
3278 if (mFrameworkScanIntervalMs > 0) {
3279 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
3280 System.currentTimeMillis() + mFrameworkScanIntervalMs,
3281 mFrameworkScanIntervalMs,
3283 mAlarmEnabled = true;
3286 mAlarmManager.cancel(mScanIntent);
3287 mAlarmEnabled = false;
3292 public void enter() {
3293 // We dont scan frequently if this is a temporary disconnect
3295 if (mTemporarilyDisconnectWifi) {
3296 mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE);
3300 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
3301 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
3302 mDefaultFrameworkScanIntervalMs);
3304 * We initiate background scanning if it is enabled, otherwise we
3305 * initiate an infrequent scan that wakes up the device to ensure
3306 * a user connects to an access point on the move
3308 if (mEnableBackgroundScan) {
3309 /* If a regular scan result is pending, do not initiate background
3310 * scan until the scan results are returned. This is needed because
3311 * initiating a background scan will cancel the regular scan and
3312 * scan results will not be returned until background scanning is
3315 if (!mScanResultIsPending) {
3316 mWifiNative.enableBackgroundScan(true);
3323 * If we have no networks saved, the supplicant stops doing the periodic scan.
3324 * The scans are useful to notify the user of the presence of an open network.
3325 * Note that these are not wake up scans.
3327 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3328 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3329 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3333 public boolean processMessage(Message message) {
3334 boolean ret = HANDLED;
3335 switch (message.what) {
3336 case CMD_NO_NETWORKS_PERIODIC_SCAN:
3337 if (mP2pConnected.get()) break;
3338 if (message.arg1 == mPeriodicScanToken &&
3339 mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3340 sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE);
3341 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3342 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3345 case WifiManager.FORGET_NETWORK:
3346 case CMD_REMOVE_NETWORK:
3347 // Set up a delayed message here. After the forget/remove is handled
3348 // the handled delayed message will determine if there is a need to
3349 // scan and continue
3350 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3351 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3354 case CMD_SET_OPERATIONAL_MODE:
3355 if (message.arg1 != CONNECT_MODE) {
3356 mOperationalMode = message.arg1;
3357 transitionTo(mScanModeState);
3360 case CMD_ENABLE_BACKGROUND_SCAN:
3361 mEnableBackgroundScan = (message.arg1 == 1);
3362 if (mEnableBackgroundScan) {
3363 mWifiNative.enableBackgroundScan(true);
3364 setScanAlarm(false);
3366 mWifiNative.enableBackgroundScan(false);
3370 /* Ignore network disconnect */
3371 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3373 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3374 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3375 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
3376 /* ConnectModeState does the rest of the handling */
3379 case CMD_START_SCAN:
3380 /* Disable background scan temporarily during a regular scan */
3381 if (mEnableBackgroundScan) {
3382 mWifiNative.enableBackgroundScan(false);
3384 /* Handled in parent state */
3387 case WifiMonitor.SCAN_RESULTS_EVENT:
3388 /* Re-enable background scan when a pending scan result is received */
3389 if (mEnableBackgroundScan && mScanResultIsPending) {
3390 mWifiNative.enableBackgroundScan(true);
3392 /* Handled in parent state */
3395 case WifiP2pService.P2P_CONNECTION_CHANGED:
3396 NetworkInfo info = (NetworkInfo) message.obj;
3397 mP2pConnected.set(info.isConnected());
3398 if (mP2pConnected.get()) {
3399 int defaultInterval = mContext.getResources().getInteger(
3400 R.integer.config_wifi_scan_interval_p2p_connected);
3401 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
3402 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
3404 mWifiNative.setScanInterval((int) scanIntervalMs/1000);
3405 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
3406 if (DBG) log("Turn on scanning after p2p disconnected");
3407 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
3408 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
3411 case CMD_REASSOCIATE:
3412 if (mTemporarilyDisconnectWifi) {
3413 // Drop a third party reconnect/reassociate if STA is
3414 // temporarily disconnected for p2p
3417 // ConnectModeState handles it
3428 public void exit() {
3429 /* No need for a background scan upon exit from a disconnected state */
3430 if (mEnableBackgroundScan) {
3431 mWifiNative.enableBackgroundScan(false);
3433 setScanAlarm(false);
3437 class WpsRunningState extends State {
3438 //Tracks the source to provide a reply
3439 private Message mSourceMessage;
3441 public void enter() {
3442 mSourceMessage = Message.obtain(getCurrentMessage());
3445 public boolean processMessage(Message message) {
3446 switch (message.what) {
3447 case WifiMonitor.WPS_SUCCESS_EVENT:
3448 // Ignore intermediate success, wait for full connection
3450 case WifiMonitor.NETWORK_CONNECTION_EVENT:
3451 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
3452 mSourceMessage.recycle();
3453 mSourceMessage = null;
3454 deferMessage(message);
3455 transitionTo(mDisconnectedState);
3457 case WifiMonitor.WPS_OVERLAP_EVENT:
3458 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3459 WifiManager.WPS_OVERLAP_ERROR);
3460 mSourceMessage.recycle();
3461 mSourceMessage = null;
3462 transitionTo(mDisconnectedState);
3464 case WifiMonitor.WPS_FAIL_EVENT:
3465 //arg1 has the reason for the failure
3466 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
3467 mSourceMessage.recycle();
3468 mSourceMessage = null;
3469 transitionTo(mDisconnectedState);
3471 case WifiMonitor.WPS_TIMEOUT_EVENT:
3472 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
3473 WifiManager.WPS_TIMED_OUT);
3474 mSourceMessage.recycle();
3475 mSourceMessage = null;
3476 transitionTo(mDisconnectedState);
3478 case WifiManager.START_WPS:
3479 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
3481 case WifiManager.CANCEL_WPS:
3482 if (mWifiNative.cancelWps()) {
3483 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
3485 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
3487 transitionTo(mDisconnectedState);
3489 /* Defer all commands that can cause connections to a different network
3490 * or put the state machine out of connect mode
3492 case CMD_STOP_DRIVER:
3493 case CMD_SET_OPERATIONAL_MODE:
3494 case WifiManager.CONNECT_NETWORK:
3495 case CMD_ENABLE_NETWORK:
3497 case CMD_REASSOCIATE:
3498 deferMessage(message);
3500 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3501 if (DBG) log("Network connection lost");
3502 handleNetworkDisconnect();
3504 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3505 // Disregard auth failure events during WPS connection. The
3506 // EAP sequence is retried several times, and there might be
3507 // failures (especially for wps pin). We will get a WPS_XXX
3508 // event at the end of the sequence anyway.
3509 if (DBG) log("Ignore auth failure during WPS connection");
3511 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3512 //Throw away supplicant state changes when WPS is running.
3513 //We will start getting supplicant state changes once we get
3514 //a WPS success or failure
3523 public void exit() {
3524 mWifiConfigStore.enableAllNetworks();
3525 mWifiConfigStore.loadConfiguredNetworks();
3529 class SoftApStartingState extends State {
3531 public void enter() {
3532 final Message message = getCurrentMessage();
3533 if (message.what == CMD_START_AP) {
3534 final WifiConfiguration config = (WifiConfiguration) message.obj;
3536 if (config == null) {
3537 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
3539 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
3540 startSoftApWithConfig(config);
3543 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
3547 public boolean processMessage(Message message) {
3548 switch(message.what) {
3549 case CMD_START_SUPPLICANT:
3550 case CMD_STOP_SUPPLICANT:
3553 case CMD_START_DRIVER:
3554 case CMD_STOP_DRIVER:
3555 case CMD_SET_OPERATIONAL_MODE:
3556 case CMD_SET_COUNTRY_CODE:
3557 case CMD_SET_FREQUENCY_BAND:
3558 case CMD_START_PACKET_FILTERING:
3559 case CMD_STOP_PACKET_FILTERING:
3560 case CMD_TETHER_STATE_CHANGE:
3561 deferMessage(message);
3563 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
3564 WifiConfiguration config = (WifiConfiguration) message.obj;
3565 if (config != null) {
3566 startSoftApWithConfig(config);
3568 loge("Softap config is null!");
3569 sendMessage(CMD_START_AP_FAILURE);
3572 case CMD_START_AP_SUCCESS:
3573 setWifiApState(WIFI_AP_STATE_ENABLED);
3574 transitionTo(mSoftApStartedState);
3576 case CMD_START_AP_FAILURE:
3577 setWifiApState(WIFI_AP_STATE_FAILED);
3578 transitionTo(mInitialState);
3587 class SoftApStartedState extends State {
3589 public boolean processMessage(Message message) {
3590 switch(message.what) {
3592 if (DBG) log("Stopping Soft AP");
3593 /* We have not tethered at this point, so we just shutdown soft Ap */
3595 mNwService.stopAccessPoint(mInterfaceName);
3596 } catch(Exception e) {
3597 loge("Exception in stopAccessPoint()");
3599 setWifiApState(WIFI_AP_STATE_DISABLED);
3600 transitionTo(mInitialState);
3603 // Ignore a start on a running access point
3605 /* Fail client mode operation when soft AP is enabled */
3606 case CMD_START_SUPPLICANT:
3607 loge("Cannot start supplicant with a running soft AP");
3608 setWifiState(WIFI_STATE_UNKNOWN);
3610 case CMD_TETHER_STATE_CHANGE:
3611 TetherStateChange stateChange = (TetherStateChange) message.obj;
3612 if (startTethering(stateChange.available)) {
3613 transitionTo(mTetheringState);
3623 class TetheringState extends State {
3625 public void enter() {
3626 /* Send ourselves a delayed message to shut down if tethering fails to notify */
3627 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3628 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3631 public boolean processMessage(Message message) {
3632 switch(message.what) {
3633 case CMD_TETHER_STATE_CHANGE:
3634 TetherStateChange stateChange = (TetherStateChange) message.obj;
3635 if (isWifiTethered(stateChange.active)) {
3636 transitionTo(mTetheredState);
3639 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3640 if (message.arg1 == mTetherToken) {
3641 loge("Failed to get tether update, shutdown soft access point");
3642 transitionTo(mSoftApStartedState);
3643 // Needs to be first thing handled
3644 sendMessageAtFrontOfQueue(CMD_STOP_AP);
3647 case CMD_START_SUPPLICANT:
3648 case CMD_STOP_SUPPLICANT:
3651 case CMD_START_DRIVER:
3652 case CMD_STOP_DRIVER:
3653 case CMD_SET_OPERATIONAL_MODE:
3654 case CMD_SET_COUNTRY_CODE:
3655 case CMD_SET_FREQUENCY_BAND:
3656 case CMD_START_PACKET_FILTERING:
3657 case CMD_STOP_PACKET_FILTERING:
3658 deferMessage(message);
3667 class TetheredState extends State {
3669 public boolean processMessage(Message message) {
3670 switch(message.what) {
3671 case CMD_TETHER_STATE_CHANGE:
3672 TetherStateChange stateChange = (TetherStateChange) message.obj;
3673 if (!isWifiTethered(stateChange.active)) {
3674 loge("Tethering reports wifi as untethered!, shut down soft Ap");
3675 setHostApRunning(null, false);
3679 if (DBG) log("Untethering before stopping AP");
3680 setWifiApState(WIFI_AP_STATE_DISABLING);
3682 transitionTo(mUntetheringState);
3683 // More work to do after untethering
3684 deferMessage(message);
3693 class UntetheringState extends State {
3695 public void enter() {
3696 /* Send ourselves a delayed message to shut down if tethering fails to notify */
3697 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
3698 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
3702 public boolean processMessage(Message message) {
3703 switch(message.what) {
3704 case CMD_TETHER_STATE_CHANGE:
3705 TetherStateChange stateChange = (TetherStateChange) message.obj;
3707 /* Wait till wifi is untethered */
3708 if (isWifiTethered(stateChange.active)) break;
3710 transitionTo(mSoftApStartedState);
3712 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
3713 if (message.arg1 == mTetherToken) {
3714 loge("Failed to get tether update, force stop access point");
3715 transitionTo(mSoftApStartedState);
3718 case CMD_START_SUPPLICANT:
3719 case CMD_STOP_SUPPLICANT:
3722 case CMD_START_DRIVER:
3723 case CMD_STOP_DRIVER:
3724 case CMD_SET_OPERATIONAL_MODE:
3725 case CMD_SET_COUNTRY_CODE:
3726 case CMD_SET_FREQUENCY_BAND:
3727 case CMD_START_PACKET_FILTERING:
3728 case CMD_STOP_PACKET_FILTERING:
3729 deferMessage(message);
3738 //State machine initiated requests can have replyTo set to null indicating
3739 //there are no recepients, we ignore those reply actions
3740 private void replyToMessage(Message msg, int what) {
3741 if (msg.replyTo == null) return;
3742 Message dstMsg = obtainMessageWithArg2(msg);
3744 mReplyChannel.replyToMessage(msg, dstMsg);
3747 private void replyToMessage(Message msg, int what, int arg1) {
3748 if (msg.replyTo == null) return;
3749 Message dstMsg = obtainMessageWithArg2(msg);
3752 mReplyChannel.replyToMessage(msg, dstMsg);
3755 private void replyToMessage(Message msg, int what, Object obj) {
3756 if (msg.replyTo == null) return;
3757 Message dstMsg = obtainMessageWithArg2(msg);
3760 mReplyChannel.replyToMessage(msg, dstMsg);
3764 * arg2 on the source message has a unique id that needs to be retained in replies
3765 * to match the request
3767 * see WifiManager for details
3769 private Message obtainMessageWithArg2(Message srcMsg) {
3770 Message msg = Message.obtain();
3771 msg.arg2 = srcMsg.arg2;