1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static android.net.wifi.WifiManager.WIFI_MODE_FULL; 20 import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF; 21 import static android.net.wifi.WifiManager.WIFI_MODE_NO_LOCKS_HELD; 22 import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY; 23 24 import android.app.AlarmManager; 25 import android.app.PendingIntent; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.database.ContentObserver; 31 import android.net.ConnectivityManager; 32 import android.net.NetworkInfo; 33 import android.net.wifi.WifiConfiguration; 34 import android.net.wifi.WifiManager; 35 import android.os.Handler; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.SystemClock; 39 import android.os.WorkSource; 40 import android.provider.Settings; 41 import android.util.Slog; 42 43 import com.android.internal.util.Protocol; 44 import com.android.internal.util.State; 45 import com.android.internal.util.StateMachine; 46 47 import java.io.FileDescriptor; 48 import java.io.PrintWriter; 49 50 /** 51 * WifiController is the class used to manage on/off state of WifiStateMachine for various operating 52 * modes (normal, airplane, wifi hotspot, etc.). 53 */ 54 public class WifiController extends StateMachine { 55 private static final String TAG = "WifiController"; 56 private static final boolean DBG = false; 57 private Context mContext; 58 private boolean mScreenOff; 59 private boolean mDeviceIdle; 60 private int mPluggedType; 61 private int mStayAwakeConditions; 62 private long mIdleMillis; 63 private int mSleepPolicy; 64 private boolean mFirstUserSignOnSeen = false; 65 66 private AlarmManager mAlarmManager; 67 private PendingIntent mIdleIntent; 68 private static final int IDLE_REQUEST = 0; 69 70 /** 71 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a 72 * Settings.Global value is not present. This timeout value is chosen as 73 * the approximate point at which the battery drain caused by Wi-Fi 74 * being enabled but not active exceeds the battery drain caused by 75 * re-establishing a connection to the mobile data network. 76 */ 77 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ 78 79 /** 80 * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a 81 * Settings.Global value is not present. This is the minimum time after wifi is disabled 82 * we'll act on an enable. Enable requests received before this delay will be deferred. 83 */ 84 private static final long DEFAULT_REENABLE_DELAY_MS = 500; 85 86 // finding that delayed messages can sometimes be delivered earlier than expected 87 // probably rounding errors.. add a margin to prevent problems 88 private static final long DEFER_MARGIN_MS = 5; 89 90 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); 91 92 private static final String ACTION_DEVICE_IDLE = 93 "com.android.server.WifiManager.action.DEVICE_IDLE"; 94 95 /* References to values tracked in WifiService */ 96 private final WifiStateMachine mWifiStateMachine; 97 private final WifiSettingsStore mSettingsStore; 98 private final WifiLockManager mWifiLockManager; 99 100 /** 101 * Temporary for computing UIDS that are responsible for starting WIFI. 102 * Protected by mWifiStateTracker lock. 103 */ 104 private final WorkSource mTmpWorkSource = new WorkSource(); 105 106 private long mReEnableDelayMillis; 107 108 private FrameworkFacade mFacade; 109 110 private static final int BASE = Protocol.BASE_WIFI_CONTROLLER; 111 112 static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1; 113 static final int CMD_SCREEN_ON = BASE + 2; 114 static final int CMD_SCREEN_OFF = BASE + 3; 115 static final int CMD_BATTERY_CHANGED = BASE + 4; 116 static final int CMD_DEVICE_IDLE = BASE + 5; 117 static final int CMD_LOCKS_CHANGED = BASE + 6; 118 static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7; 119 static final int CMD_WIFI_TOGGLED = BASE + 8; 120 static final int CMD_AIRPLANE_TOGGLED = BASE + 9; 121 static final int CMD_SET_AP = BASE + 10; 122 static final int CMD_DEFERRED_TOGGLE = BASE + 11; 123 static final int CMD_USER_PRESENT = BASE + 12; 124 static final int CMD_AP_START_FAILURE = BASE + 13; 125 static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14; 126 static final int CMD_AP_STOPPED = BASE + 15; 127 static final int CMD_STA_START_FAILURE = BASE + 16; 128 // Command used to trigger a wifi stack restart when in active mode 129 static final int CMD_RESTART_WIFI = BASE + 17; 130 // Internal command used to complete wifi stack restart 131 private static final int CMD_RESTART_WIFI_CONTINUE = BASE + 18; 132 133 private DefaultState mDefaultState = new DefaultState(); 134 private StaEnabledState mStaEnabledState = new StaEnabledState(); 135 private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState(); 136 private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState(); 137 private ApEnabledState mApEnabledState = new ApEnabledState(); 138 private DeviceActiveState mDeviceActiveState = new DeviceActiveState(); 139 private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState(); 140 private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState(); 141 private FullLockHeldState mFullLockHeldState = new FullLockHeldState(); 142 private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState(); 143 private NoLockHeldState mNoLockHeldState = new NoLockHeldState(); 144 private EcmState mEcmState = new EcmState(); 145 146 WifiController(Context context, WifiStateMachine wsm, WifiSettingsStore wss, 147 WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f) { 148 super(TAG, looper); 149 mFacade = f; 150 mContext = context; 151 mWifiStateMachine = wsm; 152 mSettingsStore = wss; 153 mWifiLockManager = wifiLockManager; 154 155 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 156 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); 157 mIdleIntent = mFacade.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); 158 159 addState(mDefaultState); 160 addState(mApStaDisabledState, mDefaultState); 161 addState(mStaEnabledState, mDefaultState); 162 addState(mDeviceActiveState, mStaEnabledState); 163 addState(mDeviceInactiveState, mStaEnabledState); 164 addState(mScanOnlyLockHeldState, mDeviceInactiveState); 165 addState(mFullLockHeldState, mDeviceInactiveState); 166 addState(mFullHighPerfLockHeldState, mDeviceInactiveState); 167 addState(mNoLockHeldState, mDeviceInactiveState); 168 addState(mStaDisabledWithScanState, mDefaultState); 169 addState(mApEnabledState, mDefaultState); 170 addState(mEcmState, mDefaultState); 171 172 boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn(); 173 boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled(); 174 boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable(); 175 176 log("isAirplaneModeOn = " + isAirplaneModeOn + 177 ", isWifiEnabled = " + isWifiEnabled + 178 ", isScanningAvailable = " + isScanningAlwaysAvailable); 179 180 if (isScanningAlwaysAvailable) { 181 setInitialState(mStaDisabledWithScanState); 182 } else { 183 setInitialState(mApStaDisabledState); 184 } 185 186 setLogRecSize(100); 187 setLogOnlyTransitions(false); 188 189 IntentFilter filter = new IntentFilter(); 190 filter.addAction(ACTION_DEVICE_IDLE); 191 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 192 filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 193 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 194 mContext.registerReceiver( 195 new BroadcastReceiver() { 196 @Override 197 public void onReceive(Context context, Intent intent) { 198 String action = intent.getAction(); 199 if (action.equals(ACTION_DEVICE_IDLE)) { 200 sendMessage(CMD_DEVICE_IDLE); 201 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 202 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 203 WifiManager.EXTRA_NETWORK_INFO); 204 } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { 205 int state = intent.getIntExtra( 206 WifiManager.EXTRA_WIFI_AP_STATE, 207 WifiManager.WIFI_AP_STATE_FAILED); 208 if (state == WifiManager.WIFI_AP_STATE_FAILED) { 209 loge(TAG + "SoftAP start failed"); 210 sendMessage(CMD_AP_START_FAILURE); 211 } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { 212 sendMessage(CMD_AP_STOPPED); 213 } 214 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 215 int state = intent.getIntExtra( 216 WifiManager.EXTRA_WIFI_STATE, 217 WifiManager.WIFI_STATE_UNKNOWN); 218 if (state == WifiManager.WIFI_STATE_UNKNOWN) { 219 loge(TAG + "Wifi turn on failed"); 220 sendMessage(CMD_STA_START_FAILURE); 221 } 222 } 223 } 224 }, 225 new IntentFilter(filter)); 226 227 initializeAndRegisterForSettingsChange(looper); 228 } 229 230 private void initializeAndRegisterForSettingsChange(Looper looper) { 231 Handler handler = new Handler(looper); 232 readStayAwakeConditions(); 233 registerForStayAwakeModeChange(handler); 234 readWifiIdleTime(); 235 registerForWifiIdleTimeChange(handler); 236 readWifiSleepPolicy(); 237 registerForWifiSleepPolicyChange(handler); 238 readWifiReEnableDelay(); 239 } 240 241 private void readStayAwakeConditions() { 242 mStayAwakeConditions = mFacade.getIntegerSetting(mContext, 243 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); 244 } 245 246 private void readWifiIdleTime() { 247 mIdleMillis = mFacade.getLongSetting(mContext, 248 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); 249 } 250 251 private void readWifiSleepPolicy() { 252 mSleepPolicy = mFacade.getIntegerSetting(mContext, 253 Settings.Global.WIFI_SLEEP_POLICY, 254 Settings.Global.WIFI_SLEEP_POLICY_NEVER); 255 } 256 257 private void readWifiReEnableDelay() { 258 mReEnableDelayMillis = mFacade.getLongSetting(mContext, 259 Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); 260 } 261 262 /** 263 * Observes settings changes to scan always mode. 264 */ 265 private void registerForStayAwakeModeChange(Handler handler) { 266 ContentObserver contentObserver = new ContentObserver(handler) { 267 @Override 268 public void onChange(boolean selfChange) { 269 readStayAwakeConditions(); 270 } 271 }; 272 273 mContext.getContentResolver().registerContentObserver( 274 Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN), 275 false, contentObserver); 276 } 277 278 /** 279 * Observes settings changes to scan always mode. 280 */ 281 private void registerForWifiIdleTimeChange(Handler handler) { 282 ContentObserver contentObserver = new ContentObserver(handler) { 283 @Override 284 public void onChange(boolean selfChange) { 285 readWifiIdleTime(); 286 } 287 }; 288 289 mContext.getContentResolver().registerContentObserver( 290 Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS), 291 false, contentObserver); 292 } 293 294 /** 295 * Observes changes to wifi sleep policy 296 */ 297 private void registerForWifiSleepPolicyChange(Handler handler) { 298 ContentObserver contentObserver = new ContentObserver(handler) { 299 @Override 300 public void onChange(boolean selfChange) { 301 readWifiSleepPolicy(); 302 } 303 }; 304 mContext.getContentResolver().registerContentObserver( 305 Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY), 306 false, contentObserver); 307 } 308 309 /** 310 * Determines whether the Wi-Fi chipset should stay awake or be put to 311 * sleep. Looks at the setting for the sleep policy and the current 312 * conditions. 313 * 314 * @see #shouldDeviceStayAwake(int) 315 */ 316 private boolean shouldWifiStayAwake(int pluggedType) { 317 if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) { 318 // Never sleep 319 return true; 320 } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && 321 (pluggedType != 0)) { 322 // Never sleep while plugged, and we're plugged 323 return true; 324 } else { 325 // Default 326 return shouldDeviceStayAwake(pluggedType); 327 } 328 } 329 330 /** 331 * Determine whether the bit value corresponding to {@code pluggedType} is set in 332 * the bit string mStayAwakeConditions. This determines whether the device should 333 * stay awake based on the current plugged type. 334 * 335 * @param pluggedType the type of plug (USB, AC, or none) for which the check is 336 * being made 337 * @return {@code true} if {@code pluggedType} indicates that the device is 338 * supposed to stay awake, {@code false} otherwise. 339 */ 340 private boolean shouldDeviceStayAwake(int pluggedType) { 341 return (mStayAwakeConditions & pluggedType) != 0; 342 } 343 344 private void updateBatteryWorkSource() { 345 mTmpWorkSource.clear(); 346 if (mDeviceIdle) { 347 mTmpWorkSource.add(mWifiLockManager.createMergedWorkSource()); 348 } 349 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); 350 } 351 352 class DefaultState extends State { 353 @Override 354 public boolean processMessage(Message msg) { 355 switch (msg.what) { 356 case CMD_SCREEN_ON: 357 mAlarmManager.cancel(mIdleIntent); 358 mScreenOff = false; 359 mDeviceIdle = false; 360 updateBatteryWorkSource(); 361 break; 362 case CMD_SCREEN_OFF: 363 mScreenOff = true; 364 /* 365 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 366 * AND the "stay on while plugged in" setting doesn't match the 367 * current power conditions (i.e, not plugged in, plugged in to USB, 368 * or plugged in to AC). 369 */ 370 if (!shouldWifiStayAwake(mPluggedType)) { 371 //Delayed shutdown if wifi is connected 372 if (mNetworkInfo.getDetailedState() == 373 NetworkInfo.DetailedState.CONNECTED) { 374 if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms"); 375 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 376 System.currentTimeMillis() + mIdleMillis, mIdleIntent); 377 } else { 378 sendMessage(CMD_DEVICE_IDLE); 379 } 380 } 381 break; 382 case CMD_DEVICE_IDLE: 383 mDeviceIdle = true; 384 updateBatteryWorkSource(); 385 break; 386 case CMD_BATTERY_CHANGED: 387 /* 388 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 389 * AND we are transitioning from a state in which the device was supposed 390 * to stay awake to a state in which it is not supposed to stay awake. 391 * If "stay awake" state is not changing, we do nothing, to avoid resetting 392 * the already-set timer. 393 */ 394 int pluggedType = msg.arg1; 395 if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType); 396 if (mScreenOff && shouldWifiStayAwake(mPluggedType) && 397 !shouldWifiStayAwake(pluggedType)) { 398 long triggerTime = System.currentTimeMillis() + mIdleMillis; 399 if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms"); 400 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 401 } 402 403 mPluggedType = pluggedType; 404 break; 405 case CMD_SET_AP: 406 case CMD_SCAN_ALWAYS_MODE_CHANGED: 407 case CMD_LOCKS_CHANGED: 408 case CMD_WIFI_TOGGLED: 409 case CMD_AIRPLANE_TOGGLED: 410 case CMD_EMERGENCY_MODE_CHANGED: 411 case CMD_EMERGENCY_CALL_STATE_CHANGED: 412 case CMD_AP_START_FAILURE: 413 case CMD_AP_STOPPED: 414 case CMD_STA_START_FAILURE: 415 case CMD_RESTART_WIFI: 416 case CMD_RESTART_WIFI_CONTINUE: 417 break; 418 case CMD_USER_PRESENT: 419 mFirstUserSignOnSeen = true; 420 break; 421 case CMD_DEFERRED_TOGGLE: 422 log("DEFERRED_TOGGLE ignored due to state change"); 423 break; 424 default: 425 throw new RuntimeException("WifiController.handleMessage " + msg.what); 426 } 427 return HANDLED; 428 } 429 430 } 431 432 class ApStaDisabledState extends State { 433 private int mDeferredEnableSerialNumber = 0; 434 private boolean mHaveDeferredEnable = false; 435 private long mDisabledTimestamp; 436 437 @Override 438 public void enter() { 439 mWifiStateMachine.setSupplicantRunning(false); 440 // Supplicant can't restart right away, so not the time we switched off 441 mDisabledTimestamp = SystemClock.elapsedRealtime(); 442 mDeferredEnableSerialNumber++; 443 mHaveDeferredEnable = false; 444 mWifiStateMachine.clearANQPCache(); 445 } 446 @Override 447 public boolean processMessage(Message msg) { 448 switch (msg.what) { 449 case CMD_WIFI_TOGGLED: 450 case CMD_AIRPLANE_TOGGLED: 451 if (mSettingsStore.isWifiToggleEnabled()) { 452 if (doDeferEnable(msg)) { 453 if (mHaveDeferredEnable) { 454 // have 2 toggles now, inc serial number an ignore both 455 mDeferredEnableSerialNumber++; 456 } 457 mHaveDeferredEnable = !mHaveDeferredEnable; 458 break; 459 } 460 if (mDeviceIdle == false) { 461 transitionTo(mDeviceActiveState); 462 } else { 463 checkLocksAndTransitionWhenDeviceIdle(); 464 } 465 } else if (mSettingsStore.isScanAlwaysAvailable()) { 466 transitionTo(mStaDisabledWithScanState); 467 } 468 break; 469 case CMD_SCAN_ALWAYS_MODE_CHANGED: 470 if (mSettingsStore.isScanAlwaysAvailable()) { 471 transitionTo(mStaDisabledWithScanState); 472 } 473 break; 474 case CMD_SET_AP: 475 if (msg.arg1 == 1) { 476 if (msg.arg2 == 0) { // previous wifi state has not been saved yet 477 mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED); 478 } 479 mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj, 480 true); 481 transitionTo(mApEnabledState); 482 } 483 break; 484 case CMD_DEFERRED_TOGGLE: 485 if (msg.arg1 != mDeferredEnableSerialNumber) { 486 log("DEFERRED_TOGGLE ignored due to serial mismatch"); 487 break; 488 } 489 log("DEFERRED_TOGGLE handled"); 490 sendMessage((Message)(msg.obj)); 491 break; 492 case CMD_RESTART_WIFI_CONTINUE: 493 transitionTo(mDeviceActiveState); 494 break; 495 default: 496 return NOT_HANDLED; 497 } 498 return HANDLED; 499 } 500 501 private boolean doDeferEnable(Message msg) { 502 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; 503 if (delaySoFar >= mReEnableDelayMillis) { 504 return false; 505 } 506 507 log("WifiController msg " + msg + " deferred for " + 508 (mReEnableDelayMillis - delaySoFar) + "ms"); 509 510 // need to defer this action. 511 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); 512 deferredMsg.obj = Message.obtain(msg); 513 deferredMsg.arg1 = ++mDeferredEnableSerialNumber; 514 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); 515 return true; 516 } 517 518 } 519 520 class StaEnabledState extends State { 521 @Override 522 public void enter() { 523 mWifiStateMachine.setSupplicantRunning(true); 524 } 525 @Override 526 public boolean processMessage(Message msg) { 527 switch (msg.what) { 528 case CMD_WIFI_TOGGLED: 529 if (! mSettingsStore.isWifiToggleEnabled()) { 530 if (mSettingsStore.isScanAlwaysAvailable()) { 531 transitionTo(mStaDisabledWithScanState); 532 } else { 533 transitionTo(mApStaDisabledState); 534 } 535 } 536 break; 537 case CMD_AIRPLANE_TOGGLED: 538 /* When wi-fi is turned off due to airplane, 539 * disable entirely (including scan) 540 */ 541 if (! mSettingsStore.isWifiToggleEnabled()) { 542 transitionTo(mApStaDisabledState); 543 } 544 break; 545 case CMD_STA_START_FAILURE: 546 if (!mSettingsStore.isScanAlwaysAvailable()) { 547 transitionTo(mApStaDisabledState); 548 } else { 549 transitionTo(mStaDisabledWithScanState); 550 } 551 break; 552 case CMD_EMERGENCY_CALL_STATE_CHANGED: 553 case CMD_EMERGENCY_MODE_CHANGED: 554 boolean getConfigWiFiDisableInECBM = mFacade.getConfigWiFiDisableInECBM(mContext); 555 log("WifiController msg " + msg + " getConfigWiFiDisableInECBM " 556 + getConfigWiFiDisableInECBM); 557 if ((msg.arg1 == 1) && getConfigWiFiDisableInECBM) { 558 transitionTo(mEcmState); 559 } 560 break; 561 case CMD_SET_AP: 562 if (msg.arg1 == 1) { 563 // remeber that we were enabled 564 mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED); 565 deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); 566 transitionTo(mApStaDisabledState); 567 } 568 break; 569 default: 570 return NOT_HANDLED; 571 572 } 573 return HANDLED; 574 } 575 } 576 577 class StaDisabledWithScanState extends State { 578 private int mDeferredEnableSerialNumber = 0; 579 private boolean mHaveDeferredEnable = false; 580 private long mDisabledTimestamp; 581 582 @Override 583 public void enter() { 584 mWifiStateMachine.setSupplicantRunning(true); 585 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); 586 mWifiStateMachine.setDriverStart(true); 587 // Supplicant can't restart right away, so not the time we switched off 588 mDisabledTimestamp = SystemClock.elapsedRealtime(); 589 mDeferredEnableSerialNumber++; 590 mHaveDeferredEnable = false; 591 mWifiStateMachine.clearANQPCache(); 592 } 593 594 @Override 595 public boolean processMessage(Message msg) { 596 switch (msg.what) { 597 case CMD_WIFI_TOGGLED: 598 if (mSettingsStore.isWifiToggleEnabled()) { 599 if (doDeferEnable(msg)) { 600 if (mHaveDeferredEnable) { 601 // have 2 toggles now, inc serial number and ignore both 602 mDeferredEnableSerialNumber++; 603 } 604 mHaveDeferredEnable = !mHaveDeferredEnable; 605 break; 606 } 607 if (mDeviceIdle == false) { 608 transitionTo(mDeviceActiveState); 609 } else { 610 checkLocksAndTransitionWhenDeviceIdle(); 611 } 612 } 613 break; 614 case CMD_AIRPLANE_TOGGLED: 615 if (mSettingsStore.isAirplaneModeOn() && 616 ! mSettingsStore.isWifiToggleEnabled()) { 617 transitionTo(mApStaDisabledState); 618 } 619 break; 620 case CMD_SCAN_ALWAYS_MODE_CHANGED: 621 if (! mSettingsStore.isScanAlwaysAvailable()) { 622 transitionTo(mApStaDisabledState); 623 } 624 break; 625 case CMD_SET_AP: 626 // Before starting tethering, turn off supplicant for scan mode 627 if (msg.arg1 == 1) { 628 mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED); 629 deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); 630 transitionTo(mApStaDisabledState); 631 } 632 break; 633 case CMD_DEFERRED_TOGGLE: 634 if (msg.arg1 != mDeferredEnableSerialNumber) { 635 log("DEFERRED_TOGGLE ignored due to serial mismatch"); 636 break; 637 } 638 logd("DEFERRED_TOGGLE handled"); 639 sendMessage((Message)(msg.obj)); 640 break; 641 default: 642 return NOT_HANDLED; 643 } 644 return HANDLED; 645 } 646 647 private boolean doDeferEnable(Message msg) { 648 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; 649 if (delaySoFar >= mReEnableDelayMillis) { 650 return false; 651 } 652 653 log("WifiController msg " + msg + " deferred for " + 654 (mReEnableDelayMillis - delaySoFar) + "ms"); 655 656 // need to defer this action. 657 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); 658 deferredMsg.obj = Message.obtain(msg); 659 deferredMsg.arg1 = ++mDeferredEnableSerialNumber; 660 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); 661 return true; 662 } 663 664 } 665 666 /** 667 * Only transition out of this state when AP failed to start or AP is stopped. 668 */ 669 class ApEnabledState extends State { 670 /** 671 * Save the pending state when stopping the AP, so that it will transition 672 * to the correct state when AP is stopped. This is to avoid a possible 673 * race condition where the new state might try to update the driver/interface 674 * state before AP is completely torn down. 675 */ 676 private State mPendingState = null; 677 678 /** 679 * Determine the next state based on the current settings (e.g. saved 680 * wifi state). 681 */ 682 private State getNextWifiState() { 683 if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) { 684 return mDeviceActiveState; 685 } 686 687 if (mSettingsStore.isScanAlwaysAvailable()) { 688 return mStaDisabledWithScanState; 689 } 690 691 return mApStaDisabledState; 692 } 693 694 @Override 695 public boolean processMessage(Message msg) { 696 switch (msg.what) { 697 case CMD_AIRPLANE_TOGGLED: 698 if (mSettingsStore.isAirplaneModeOn()) { 699 mWifiStateMachine.setHostApRunning(null, false); 700 mPendingState = mApStaDisabledState; 701 } 702 break; 703 case CMD_WIFI_TOGGLED: 704 if (mSettingsStore.isWifiToggleEnabled()) { 705 mWifiStateMachine.setHostApRunning(null, false); 706 mPendingState = mDeviceActiveState; 707 } 708 break; 709 case CMD_SET_AP: 710 if (msg.arg1 == 0) { 711 mWifiStateMachine.setHostApRunning(null, false); 712 mPendingState = getNextWifiState(); 713 } 714 break; 715 case CMD_AP_STOPPED: 716 if (mPendingState == null) { 717 /** 718 * Stop triggered internally, either tether notification 719 * timed out or wifi is untethered for some reason. 720 */ 721 mPendingState = getNextWifiState(); 722 } 723 if (mPendingState == mDeviceActiveState && mDeviceIdle) { 724 checkLocksAndTransitionWhenDeviceIdle(); 725 } else { 726 // go ahead and transition because we are not idle or we are not going 727 // to the active state. 728 transitionTo(mPendingState); 729 } 730 break; 731 case CMD_EMERGENCY_CALL_STATE_CHANGED: 732 case CMD_EMERGENCY_MODE_CHANGED: 733 if (msg.arg1 == 1) { 734 mWifiStateMachine.setHostApRunning(null, false); 735 mPendingState = mEcmState; 736 } 737 break; 738 case CMD_AP_START_FAILURE: 739 transitionTo(getNextWifiState()); 740 break; 741 default: 742 return NOT_HANDLED; 743 } 744 return HANDLED; 745 } 746 } 747 748 class EcmState extends State { 749 // we can enter EcmState either because an emergency call started or because 750 // emergency callback mode started. This count keeps track of how many such 751 // events happened; so we can exit after all are undone 752 753 private int mEcmEntryCount; 754 @Override 755 public void enter() { 756 mWifiStateMachine.setSupplicantRunning(false); 757 mWifiStateMachine.clearANQPCache(); 758 mEcmEntryCount = 1; 759 } 760 761 @Override 762 public boolean processMessage(Message msg) { 763 if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED) { 764 if (msg.arg1 == 1) { 765 // nothing to do - just says emergency call started 766 mEcmEntryCount++; 767 } else if (msg.arg1 == 0) { 768 // emergency call ended 769 decrementCountAndReturnToAppropriateState(); 770 } 771 return HANDLED; 772 } else if (msg.what == CMD_EMERGENCY_MODE_CHANGED) { 773 774 if (msg.arg1 == 1) { 775 // Transitioned into emergency callback mode 776 mEcmEntryCount++; 777 } else if (msg.arg1 == 0) { 778 // out of emergency callback mode 779 decrementCountAndReturnToAppropriateState(); 780 } 781 return HANDLED; 782 } else { 783 return NOT_HANDLED; 784 } 785 } 786 787 private void decrementCountAndReturnToAppropriateState() { 788 boolean exitEcm = false; 789 790 if (mEcmEntryCount == 0) { 791 loge("mEcmEntryCount is 0; exiting Ecm"); 792 exitEcm = true; 793 } else if (--mEcmEntryCount == 0) { 794 exitEcm = true; 795 } 796 797 if (exitEcm) { 798 if (mSettingsStore.isWifiToggleEnabled()) { 799 if (mDeviceIdle == false) { 800 transitionTo(mDeviceActiveState); 801 } else { 802 checkLocksAndTransitionWhenDeviceIdle(); 803 } 804 } else if (mSettingsStore.isScanAlwaysAvailable()) { 805 transitionTo(mStaDisabledWithScanState); 806 } else { 807 transitionTo(mApStaDisabledState); 808 } 809 } 810 } 811 } 812 813 /* Parent: StaEnabledState */ 814 class DeviceActiveState extends State { 815 @Override 816 public void enter() { 817 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 818 mWifiStateMachine.setDriverStart(true); 819 mWifiStateMachine.setHighPerfModeEnabled(false); 820 } 821 822 @Override 823 public boolean processMessage(Message msg) { 824 if (msg.what == CMD_DEVICE_IDLE) { 825 checkLocksAndTransitionWhenDeviceIdle(); 826 // We let default state handle the rest of work 827 } else if (msg.what == CMD_USER_PRESENT) { 828 // TLS networks can't connect until user unlocks keystore. KeyStore 829 // unlocks when the user punches PIN after the reboot. So use this 830 // trigger to get those networks connected. 831 if (mFirstUserSignOnSeen == false) { 832 mWifiStateMachine.reloadTlsNetworksAndReconnect(); 833 } 834 mFirstUserSignOnSeen = true; 835 return HANDLED; 836 } else if (msg.what == CMD_RESTART_WIFI) { 837 deferMessage(obtainMessage(CMD_RESTART_WIFI_CONTINUE)); 838 transitionTo(mApStaDisabledState); 839 return HANDLED; 840 } 841 return NOT_HANDLED; 842 } 843 } 844 845 /* Parent: StaEnabledState */ 846 class DeviceInactiveState extends State { 847 @Override 848 public boolean processMessage(Message msg) { 849 switch (msg.what) { 850 case CMD_LOCKS_CHANGED: 851 checkLocksAndTransitionWhenDeviceIdle(); 852 updateBatteryWorkSource(); 853 return HANDLED; 854 case CMD_SCREEN_ON: 855 transitionTo(mDeviceActiveState); 856 // More work in default state 857 return NOT_HANDLED; 858 default: 859 return NOT_HANDLED; 860 } 861 } 862 } 863 864 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */ 865 class ScanOnlyLockHeldState extends State { 866 @Override 867 public void enter() { 868 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 869 mWifiStateMachine.setDriverStart(true); 870 } 871 } 872 873 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */ 874 class FullLockHeldState extends State { 875 @Override 876 public void enter() { 877 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 878 mWifiStateMachine.setDriverStart(true); 879 mWifiStateMachine.setHighPerfModeEnabled(false); 880 } 881 } 882 883 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */ 884 class FullHighPerfLockHeldState extends State { 885 @Override 886 public void enter() { 887 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 888 mWifiStateMachine.setDriverStart(true); 889 mWifiStateMachine.setHighPerfModeEnabled(true); 890 } 891 } 892 893 /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */ 894 class NoLockHeldState extends State { 895 @Override 896 public void enter() { 897 mWifiStateMachine.setDriverStart(false); 898 } 899 } 900 901 private void checkLocksAndTransitionWhenDeviceIdle() { 902 switch (mWifiLockManager.getStrongestLockMode()) { 903 case WIFI_MODE_NO_LOCKS_HELD: 904 if (mSettingsStore.isScanAlwaysAvailable()) { 905 transitionTo(mScanOnlyLockHeldState); 906 } else { 907 transitionTo(mNoLockHeldState); 908 } 909 break; 910 case WIFI_MODE_FULL: 911 transitionTo(mFullLockHeldState); 912 break; 913 case WIFI_MODE_FULL_HIGH_PERF: 914 transitionTo(mFullHighPerfLockHeldState); 915 break; 916 case WIFI_MODE_SCAN_ONLY: 917 transitionTo(mScanOnlyLockHeldState); 918 break; 919 } 920 } 921 922 @Override 923 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 924 super.dump(fd, pw, args); 925 926 pw.println("mScreenOff " + mScreenOff); 927 pw.println("mDeviceIdle " + mDeviceIdle); 928 pw.println("mPluggedType " + mPluggedType); 929 pw.println("mIdleMillis " + mIdleMillis); 930 pw.println("mSleepPolicy " + mSleepPolicy); 931 } 932 } 933