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