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