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