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