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 android.app.AlarmManager; 20 import android.app.PendingIntent; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.database.ContentObserver; 26 import android.net.ConnectivityManager; 27 import android.net.NetworkInfo; 28 import android.net.wifi.WifiConfiguration; 29 import android.net.wifi.WifiManager; 30 import static android.net.wifi.WifiManager.WIFI_MODE_FULL; 31 import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF; 32 import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY; 33 import android.net.wifi.WifiStateMachine; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.SystemClock; 38 import android.os.WorkSource; 39 import android.provider.Settings; 40 import android.util.Slog; 41 42 import com.android.internal.util.Protocol; 43 import com.android.internal.util.State; 44 import com.android.internal.util.StateMachine; 45 import com.android.server.wifi.WifiService.LockList; 46 47 import java.io.FileDescriptor; 48 import java.io.PrintWriter; 49 50 class WifiController extends StateMachine { 51 private static final String TAG = "WifiController"; 52 private static final boolean DBG = false; 53 private Context mContext; 54 private boolean mScreenOff; 55 private boolean mDeviceIdle; 56 private int mPluggedType; 57 private int mStayAwakeConditions; 58 private long mIdleMillis; 59 private int mSleepPolicy; 60 61 private AlarmManager mAlarmManager; 62 private PendingIntent mIdleIntent; 63 private static final int IDLE_REQUEST = 0; 64 65 /** 66 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a 67 * Settings.Global value is not present. This timeout value is chosen as 68 * the approximate point at which the battery drain caused by Wi-Fi 69 * being enabled but not active exceeds the battery drain caused by 70 * re-establishing a connection to the mobile data network. 71 */ 72 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ 73 74 /** 75 * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a 76 * Settings.Global value is not present. This is the minimum time after wifi is disabled 77 * we'll act on an enable. Enable requests received before this delay will be deferred. 78 */ 79 private static final long DEFAULT_REENABLE_DELAY_MS = 500; 80 81 // finding that delayed messages can sometimes be delivered earlier than expected 82 // probably rounding errors.. add a margin to prevent problems 83 private static final long DEFER_MARGIN_MS = 5; 84 85 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); 86 87 private static final String ACTION_DEVICE_IDLE = 88 "com.android.server.WifiManager.action.DEVICE_IDLE"; 89 90 /* References to values tracked in WifiService */ 91 final WifiStateMachine mWifiStateMachine; 92 final WifiSettingsStore mSettingsStore; 93 final LockList mLocks; 94 95 /** 96 * Temporary for computing UIDS that are responsible for starting WIFI. 97 * Protected by mWifiStateTracker lock. 98 */ 99 private final WorkSource mTmpWorkSource = new WorkSource(); 100 101 private long mReEnableDelayMillis; 102 103 private static final int BASE = Protocol.BASE_WIFI_CONTROLLER; 104 105 static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1; 106 static final int CMD_SCREEN_ON = BASE + 2; 107 static final int CMD_SCREEN_OFF = BASE + 3; 108 static final int CMD_BATTERY_CHANGED = BASE + 4; 109 static final int CMD_DEVICE_IDLE = BASE + 5; 110 static final int CMD_LOCKS_CHANGED = BASE + 6; 111 static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7; 112 static final int CMD_WIFI_TOGGLED = BASE + 8; 113 static final int CMD_AIRPLANE_TOGGLED = BASE + 9; 114 static final int CMD_SET_AP = BASE + 10; 115 static final int CMD_DEFERRED_TOGGLE = BASE + 11; 116 117 private DefaultState mDefaultState = new DefaultState(); 118 private StaEnabledState mStaEnabledState = new StaEnabledState(); 119 private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState(); 120 private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState(); 121 private ApEnabledState mApEnabledState = new ApEnabledState(); 122 private DeviceActiveState mDeviceActiveState = new DeviceActiveState(); 123 private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState(); 124 private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState(); 125 private FullLockHeldState mFullLockHeldState = new FullLockHeldState(); 126 private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState(); 127 private NoLockHeldState mNoLockHeldState = new NoLockHeldState(); 128 private EcmState mEcmState = new EcmState(); 129 130 WifiController(Context context, WifiService service, Looper looper) { 131 super(TAG, looper); 132 mContext = context; 133 mWifiStateMachine = service.mWifiStateMachine; 134 mSettingsStore = service.mSettingsStore; 135 mLocks = service.mLocks; 136 137 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 138 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); 139 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); 140 141 addState(mDefaultState); 142 addState(mApStaDisabledState, mDefaultState); 143 addState(mStaEnabledState, mDefaultState); 144 addState(mDeviceActiveState, mStaEnabledState); 145 addState(mDeviceInactiveState, mStaEnabledState); 146 addState(mScanOnlyLockHeldState, mDeviceInactiveState); 147 addState(mFullLockHeldState, mDeviceInactiveState); 148 addState(mFullHighPerfLockHeldState, mDeviceInactiveState); 149 addState(mNoLockHeldState, mDeviceInactiveState); 150 addState(mStaDisabledWithScanState, mDefaultState); 151 addState(mApEnabledState, mDefaultState); 152 addState(mEcmState, mDefaultState); 153 if (mSettingsStore.isScanAlwaysAvailable()) { 154 setInitialState(mStaDisabledWithScanState); 155 } else { 156 setInitialState(mApStaDisabledState); 157 } 158 setLogRecSize(100); 159 setLogOnlyTransitions(false); 160 161 IntentFilter filter = new IntentFilter(); 162 filter.addAction(ACTION_DEVICE_IDLE); 163 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 164 mContext.registerReceiver( 165 new BroadcastReceiver() { 166 @Override 167 public void onReceive(Context context, Intent intent) { 168 String action = intent.getAction(); 169 if (action.equals(ACTION_DEVICE_IDLE)) { 170 sendMessage(CMD_DEVICE_IDLE); 171 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 172 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 173 WifiManager.EXTRA_NETWORK_INFO); 174 } 175 } 176 }, 177 new IntentFilter(filter)); 178 179 initializeAndRegisterForSettingsChange(looper); 180 } 181 182 private void initializeAndRegisterForSettingsChange(Looper looper) { 183 Handler handler = new Handler(looper); 184 readStayAwakeConditions(); 185 registerForStayAwakeModeChange(handler); 186 readWifiIdleTime(); 187 registerForWifiIdleTimeChange(handler); 188 readWifiSleepPolicy(); 189 registerForWifiSleepPolicyChange(handler); 190 readWifiReEnableDelay(); 191 } 192 193 private void readStayAwakeConditions() { 194 mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(), 195 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); 196 } 197 198 private void readWifiIdleTime() { 199 mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(), 200 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); 201 } 202 203 private void readWifiSleepPolicy() { 204 mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(), 205 Settings.Global.WIFI_SLEEP_POLICY, 206 Settings.Global.WIFI_SLEEP_POLICY_NEVER); 207 } 208 209 private void readWifiReEnableDelay() { 210 mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(), 211 Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); 212 } 213 214 /** 215 * Observes settings changes to scan always mode. 216 */ 217 private void registerForStayAwakeModeChange(Handler handler) { 218 ContentObserver contentObserver = new ContentObserver(handler) { 219 @Override 220 public void onChange(boolean selfChange) { 221 readStayAwakeConditions(); 222 } 223 }; 224 225 mContext.getContentResolver().registerContentObserver( 226 Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN), 227 false, contentObserver); 228 } 229 230 /** 231 * Observes settings changes to scan always mode. 232 */ 233 private void registerForWifiIdleTimeChange(Handler handler) { 234 ContentObserver contentObserver = new ContentObserver(handler) { 235 @Override 236 public void onChange(boolean selfChange) { 237 readWifiIdleTime(); 238 } 239 }; 240 241 mContext.getContentResolver().registerContentObserver( 242 Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS), 243 false, contentObserver); 244 } 245 246 /** 247 * Observes changes to wifi sleep policy 248 */ 249 private void registerForWifiSleepPolicyChange(Handler handler) { 250 ContentObserver contentObserver = new ContentObserver(handler) { 251 @Override 252 public void onChange(boolean selfChange) { 253 readWifiSleepPolicy(); 254 } 255 }; 256 mContext.getContentResolver().registerContentObserver( 257 Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY), 258 false, contentObserver); 259 } 260 261 /** 262 * Determines whether the Wi-Fi chipset should stay awake or be put to 263 * sleep. Looks at the setting for the sleep policy and the current 264 * conditions. 265 * 266 * @see #shouldDeviceStayAwake(int) 267 */ 268 private boolean shouldWifiStayAwake(int pluggedType) { 269 if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) { 270 // Never sleep 271 return true; 272 } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && 273 (pluggedType != 0)) { 274 // Never sleep while plugged, and we're plugged 275 return true; 276 } else { 277 // Default 278 return shouldDeviceStayAwake(pluggedType); 279 } 280 } 281 282 /** 283 * Determine whether the bit value corresponding to {@code pluggedType} is set in 284 * the bit string mStayAwakeConditions. This determines whether the device should 285 * stay awake based on the current plugged type. 286 * 287 * @param pluggedType the type of plug (USB, AC, or none) for which the check is 288 * being made 289 * @return {@code true} if {@code pluggedType} indicates that the device is 290 * supposed to stay awake, {@code false} otherwise. 291 */ 292 private boolean shouldDeviceStayAwake(int pluggedType) { 293 return (mStayAwakeConditions & pluggedType) != 0; 294 } 295 296 private void updateBatteryWorkSource() { 297 mTmpWorkSource.clear(); 298 if (mDeviceIdle) { 299 mLocks.updateWorkSource(mTmpWorkSource); 300 } 301 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); 302 } 303 304 class DefaultState extends State { 305 @Override 306 public boolean processMessage(Message msg) { 307 switch (msg.what) { 308 case CMD_SCREEN_ON: 309 mAlarmManager.cancel(mIdleIntent); 310 mScreenOff = false; 311 mDeviceIdle = false; 312 updateBatteryWorkSource(); 313 break; 314 case CMD_SCREEN_OFF: 315 mScreenOff = true; 316 /* 317 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 318 * AND the "stay on while plugged in" setting doesn't match the 319 * current power conditions (i.e, not plugged in, plugged in to USB, 320 * or plugged in to AC). 321 */ 322 if (!shouldWifiStayAwake(mPluggedType)) { 323 //Delayed shutdown if wifi is connected 324 if (mNetworkInfo.getDetailedState() == 325 NetworkInfo.DetailedState.CONNECTED) { 326 if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms"); 327 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 328 System.currentTimeMillis() + mIdleMillis, mIdleIntent); 329 } else { 330 sendMessage(CMD_DEVICE_IDLE); 331 } 332 } 333 break; 334 case CMD_DEVICE_IDLE: 335 mDeviceIdle = true; 336 updateBatteryWorkSource(); 337 break; 338 case CMD_BATTERY_CHANGED: 339 /* 340 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 341 * AND we are transitioning from a state in which the device was supposed 342 * to stay awake to a state in which it is not supposed to stay awake. 343 * If "stay awake" state is not changing, we do nothing, to avoid resetting 344 * the already-set timer. 345 */ 346 int pluggedType = msg.arg1; 347 if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType); 348 if (mScreenOff && shouldWifiStayAwake(mPluggedType) && 349 !shouldWifiStayAwake(pluggedType)) { 350 long triggerTime = System.currentTimeMillis() + mIdleMillis; 351 if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms"); 352 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 353 } 354 355 mPluggedType = pluggedType; 356 break; 357 case CMD_SET_AP: 358 case CMD_SCAN_ALWAYS_MODE_CHANGED: 359 case CMD_LOCKS_CHANGED: 360 case CMD_WIFI_TOGGLED: 361 case CMD_AIRPLANE_TOGGLED: 362 case CMD_EMERGENCY_MODE_CHANGED: 363 break; 364 case CMD_DEFERRED_TOGGLE: 365 log("DEFERRED_TOGGLE ignored due to state change"); 366 break; 367 default: 368 throw new RuntimeException("WifiController.handleMessage " + msg.what); 369 } 370 return HANDLED; 371 } 372 373 } 374 375 class ApStaDisabledState extends State { 376 private int mDeferredEnableSerialNumber = 0; 377 private boolean mHaveDeferredEnable = false; 378 private long mDisabledTimestamp; 379 380 @Override 381 public void enter() { 382 mWifiStateMachine.setSupplicantRunning(false); 383 // Supplicant can't restart right away, so not the time we switched off 384 mDisabledTimestamp = SystemClock.elapsedRealtime(); 385 mDeferredEnableSerialNumber++; 386 mHaveDeferredEnable = false; 387 } 388 @Override 389 public boolean processMessage(Message msg) { 390 switch (msg.what) { 391 case CMD_WIFI_TOGGLED: 392 case CMD_AIRPLANE_TOGGLED: 393 if (mSettingsStore.isWifiToggleEnabled()) { 394 if (doDeferEnable(msg)) { 395 if (mHaveDeferredEnable) { 396 // have 2 toggles now, inc serial number an ignore both 397 mDeferredEnableSerialNumber++; 398 } 399 mHaveDeferredEnable = !mHaveDeferredEnable; 400 break; 401 } 402 if (mDeviceIdle == false) { 403 transitionTo(mDeviceActiveState); 404 } else { 405 checkLocksAndTransitionWhenDeviceIdle(); 406 } 407 } 408 break; 409 case CMD_SCAN_ALWAYS_MODE_CHANGED: 410 if (mSettingsStore.isScanAlwaysAvailable()) { 411 transitionTo(mStaDisabledWithScanState); 412 } 413 break; 414 case CMD_SET_AP: 415 if (msg.arg1 == 1) { 416 mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj, 417 true); 418 transitionTo(mApEnabledState); 419 } 420 break; 421 case CMD_DEFERRED_TOGGLE: 422 if (msg.arg1 != mDeferredEnableSerialNumber) { 423 log("DEFERRED_TOGGLE ignored due to serial mismatch"); 424 break; 425 } 426 log("DEFERRED_TOGGLE handled"); 427 sendMessage((Message)(msg.obj)); 428 break; 429 default: 430 return NOT_HANDLED; 431 } 432 return HANDLED; 433 } 434 435 private boolean doDeferEnable(Message msg) { 436 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; 437 if (delaySoFar >= mReEnableDelayMillis) { 438 return false; 439 } 440 441 log("WifiController msg " + msg + " deferred for " + 442 (mReEnableDelayMillis - delaySoFar) + "ms"); 443 444 // need to defer this action. 445 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); 446 deferredMsg.obj = Message.obtain(msg); 447 deferredMsg.arg1 = ++mDeferredEnableSerialNumber; 448 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); 449 return true; 450 } 451 452 } 453 454 class StaEnabledState extends State { 455 @Override 456 public void enter() { 457 mWifiStateMachine.setSupplicantRunning(true); 458 } 459 @Override 460 public boolean processMessage(Message msg) { 461 switch (msg.what) { 462 case CMD_WIFI_TOGGLED: 463 if (! mSettingsStore.isWifiToggleEnabled()) { 464 if (mSettingsStore.isScanAlwaysAvailable()) { 465 transitionTo(mStaDisabledWithScanState); 466 } else { 467 transitionTo(mApStaDisabledState); 468 } 469 } 470 break; 471 case CMD_AIRPLANE_TOGGLED: 472 /* When wi-fi is turned off due to airplane, 473 * disable entirely (including scan) 474 */ 475 if (! mSettingsStore.isWifiToggleEnabled()) { 476 transitionTo(mApStaDisabledState); 477 } 478 break; 479 case CMD_EMERGENCY_MODE_CHANGED: 480 if (msg.arg1 == 1) { 481 transitionTo(mEcmState); 482 break; 483 } 484 default: 485 return NOT_HANDLED; 486 487 } 488 return HANDLED; 489 } 490 } 491 492 class StaDisabledWithScanState extends State { 493 private int mDeferredEnableSerialNumber = 0; 494 private boolean mHaveDeferredEnable = false; 495 private long mDisabledTimestamp; 496 497 @Override 498 public void enter() { 499 mWifiStateMachine.setSupplicantRunning(true); 500 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); 501 mWifiStateMachine.setDriverStart(true); 502 // Supplicant can't restart right away, so not the time we switched off 503 mDisabledTimestamp = SystemClock.elapsedRealtime(); 504 mDeferredEnableSerialNumber++; 505 mHaveDeferredEnable = false; 506 } 507 508 @Override 509 public boolean processMessage(Message msg) { 510 switch (msg.what) { 511 case CMD_WIFI_TOGGLED: 512 if (mSettingsStore.isWifiToggleEnabled()) { 513 if (doDeferEnable(msg)) { 514 if (mHaveDeferredEnable) { 515 // have 2 toggles now, inc serial number and ignore both 516 mDeferredEnableSerialNumber++; 517 } 518 mHaveDeferredEnable = !mHaveDeferredEnable; 519 break; 520 } 521 if (mDeviceIdle == false) { 522 transitionTo(mDeviceActiveState); 523 } else { 524 checkLocksAndTransitionWhenDeviceIdle(); 525 } 526 } 527 break; 528 case CMD_AIRPLANE_TOGGLED: 529 if (mSettingsStore.isAirplaneModeOn() && 530 ! mSettingsStore.isWifiToggleEnabled()) { 531 transitionTo(mApStaDisabledState); 532 } 533 case CMD_SCAN_ALWAYS_MODE_CHANGED: 534 if (! mSettingsStore.isScanAlwaysAvailable()) { 535 transitionTo(mApStaDisabledState); 536 } 537 break; 538 case CMD_SET_AP: 539 // Before starting tethering, turn off supplicant for scan mode 540 if (msg.arg1 == 1) { 541 deferMessage(msg); 542 transitionTo(mApStaDisabledState); 543 } 544 break; 545 case CMD_DEFERRED_TOGGLE: 546 if (msg.arg1 != mDeferredEnableSerialNumber) { 547 log("DEFERRED_TOGGLE ignored due to serial mismatch"); 548 break; 549 } 550 logd("DEFERRED_TOGGLE handled"); 551 sendMessage((Message)(msg.obj)); 552 break; 553 default: 554 return NOT_HANDLED; 555 } 556 return HANDLED; 557 } 558 559 private boolean doDeferEnable(Message msg) { 560 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; 561 if (delaySoFar >= mReEnableDelayMillis) { 562 return false; 563 } 564 565 log("WifiController msg " + msg + " deferred for " + 566 (mReEnableDelayMillis - delaySoFar) + "ms"); 567 568 // need to defer this action. 569 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); 570 deferredMsg.obj = Message.obtain(msg); 571 deferredMsg.arg1 = ++mDeferredEnableSerialNumber; 572 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); 573 return true; 574 } 575 576 } 577 578 class ApEnabledState extends State { 579 @Override 580 public boolean processMessage(Message msg) { 581 switch (msg.what) { 582 case CMD_AIRPLANE_TOGGLED: 583 if (mSettingsStore.isAirplaneModeOn()) { 584 mWifiStateMachine.setHostApRunning(null, false); 585 transitionTo(mApStaDisabledState); 586 } 587 break; 588 case CMD_SET_AP: 589 if (msg.arg1 == 0) { 590 mWifiStateMachine.setHostApRunning(null, false); 591 transitionTo(mApStaDisabledState); 592 } 593 break; 594 default: 595 return NOT_HANDLED; 596 } 597 return HANDLED; 598 } 599 } 600 601 class EcmState extends State { 602 @Override 603 public void enter() { 604 mWifiStateMachine.setSupplicantRunning(false); 605 } 606 607 @Override 608 public boolean processMessage(Message msg) { 609 if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) { 610 if (mSettingsStore.isWifiToggleEnabled()) { 611 if (mDeviceIdle == false) { 612 transitionTo(mDeviceActiveState); 613 } else { 614 checkLocksAndTransitionWhenDeviceIdle(); 615 } 616 } else if (mSettingsStore.isScanAlwaysAvailable()) { 617 transitionTo(mStaDisabledWithScanState); 618 } else { 619 transitionTo(mApStaDisabledState); 620 } 621 return HANDLED; 622 } else { 623 return NOT_HANDLED; 624 } 625 } 626 } 627 628 /* Parent: StaEnabledState */ 629 class DeviceActiveState extends State { 630 @Override 631 public void enter() { 632 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 633 mWifiStateMachine.setDriverStart(true); 634 mWifiStateMachine.setHighPerfModeEnabled(false); 635 } 636 637 @Override 638 public boolean processMessage(Message msg) { 639 if (msg.what == CMD_DEVICE_IDLE) { 640 checkLocksAndTransitionWhenDeviceIdle(); 641 // We let default state handle the rest of work 642 } 643 return NOT_HANDLED; 644 } 645 } 646 647 /* Parent: StaEnabledState */ 648 class DeviceInactiveState extends State { 649 @Override 650 public boolean processMessage(Message msg) { 651 switch (msg.what) { 652 case CMD_LOCKS_CHANGED: 653 checkLocksAndTransitionWhenDeviceIdle(); 654 updateBatteryWorkSource(); 655 return HANDLED; 656 case CMD_SCREEN_ON: 657 transitionTo(mDeviceActiveState); 658 // More work in default state 659 return NOT_HANDLED; 660 default: 661 return NOT_HANDLED; 662 } 663 } 664 } 665 666 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */ 667 class ScanOnlyLockHeldState extends State { 668 @Override 669 public void enter() { 670 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE); 671 mWifiStateMachine.setDriverStart(true); 672 } 673 } 674 675 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */ 676 class FullLockHeldState extends State { 677 @Override 678 public void enter() { 679 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 680 mWifiStateMachine.setDriverStart(true); 681 mWifiStateMachine.setHighPerfModeEnabled(false); 682 } 683 } 684 685 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */ 686 class FullHighPerfLockHeldState extends State { 687 @Override 688 public void enter() { 689 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); 690 mWifiStateMachine.setDriverStart(true); 691 mWifiStateMachine.setHighPerfModeEnabled(true); 692 } 693 } 694 695 /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */ 696 class NoLockHeldState extends State { 697 @Override 698 public void enter() { 699 mWifiStateMachine.setDriverStart(false); 700 } 701 } 702 703 private void checkLocksAndTransitionWhenDeviceIdle() { 704 if (mLocks.hasLocks()) { 705 switch (mLocks.getStrongestLockMode()) { 706 case WIFI_MODE_FULL: 707 transitionTo(mFullLockHeldState); 708 break; 709 case WIFI_MODE_FULL_HIGH_PERF: 710 transitionTo(mFullHighPerfLockHeldState); 711 break; 712 case WIFI_MODE_SCAN_ONLY: 713 transitionTo(mScanOnlyLockHeldState); 714 break; 715 default: 716 loge("Illegal lock " + mLocks.getStrongestLockMode()); 717 } 718 } else { 719 if (mSettingsStore.isScanAlwaysAvailable()) { 720 transitionTo(mScanOnlyLockHeldState); 721 } else { 722 transitionTo(mNoLockHeldState); 723 } 724 } 725 } 726 727 @Override 728 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 729 super.dump(fd, pw, args); 730 731 pw.println("mScreenOff " + mScreenOff); 732 pw.println("mDeviceIdle " + mDeviceIdle); 733 pw.println("mPluggedType " + mPluggedType); 734 pw.println("mIdleMillis " + mIdleMillis); 735 pw.println("mSleepPolicy " + mSleepPolicy); 736 } 737 } 738