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