1 /* 2 * Copyright (C) 2015 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 package com.android.car; 17 18 import android.annotation.Nullable; 19 import android.annotation.UserIdInt; 20 import android.app.ActivityManager; 21 import android.car.Car; 22 import android.car.hardware.power.CarPowerManager.CarPowerStateListener; 23 import android.car.hardware.power.ICarPower; 24 import android.car.hardware.power.ICarPowerStateListener; 25 import android.car.userlib.CarUserManagerHelper; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.UserInfo; 30 import android.content.res.Resources; 31 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq; 32 import android.os.Build; 33 import android.os.Handler; 34 import android.os.HandlerThread; 35 import android.os.IBinder; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.PowerManager; 39 import android.os.RemoteCallbackList; 40 import android.os.RemoteException; 41 import android.os.SystemClock; 42 import android.os.SystemProperties; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.util.Log; 46 47 import com.android.car.am.ContinuousBlankActivity; 48 import com.android.car.hal.PowerHalService; 49 import com.android.car.hal.PowerHalService.PowerState; 50 import com.android.car.systeminterface.SystemInterface; 51 import com.android.car.user.CarUserNoticeService; 52 import com.android.internal.annotations.GuardedBy; 53 import com.android.internal.annotations.VisibleForTesting; 54 55 import java.io.PrintWriter; 56 import java.util.HashSet; 57 import java.util.LinkedList; 58 import java.util.List; 59 import java.util.Set; 60 import java.util.Timer; 61 import java.util.TimerTask; 62 63 /** 64 * Power Management service class for cars. Controls the power states and interacts with other 65 * parts of the system to ensure its own state. 66 */ 67 public class CarPowerManagementService extends ICarPower.Stub implements 68 CarServiceBase, PowerHalService.PowerEventListener { 69 70 private final Object mLock = new Object(); 71 private final Object mSimulationWaitObject = new Object(); 72 73 private final Context mContext; 74 private final PowerHalService mHal; 75 private final SystemInterface mSystemInterface; 76 // The listeners that complete simply by returning from onStateChanged() 77 private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList(); 78 // The listeners that must indicate asynchronous completion by calling finished(). 79 private final PowerManagerCallbackList mPowerManagerListenersWithCompletion = 80 new PowerManagerCallbackList(); 81 82 @GuardedBy("mSimulationWaitObject") 83 private boolean mWakeFromSimulatedSleep; 84 @GuardedBy("mSimulationWaitObject") 85 private boolean mInSimulatedDeepSleepMode; 86 87 @GuardedBy("mLock") 88 private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>(); 89 @GuardedBy("mLock") 90 private CpmsState mCurrentState; 91 @GuardedBy("mLock") 92 private Timer mTimer; 93 @GuardedBy("mLock") 94 private long mProcessingStartTime; 95 @GuardedBy("mLock") 96 private long mLastSleepEntryTime; 97 @GuardedBy("mLock") 98 private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>(); 99 @GuardedBy("mLock") 100 private HandlerThread mHandlerThread; 101 @GuardedBy("mLock") 102 private PowerHandler mHandler; 103 @GuardedBy("mLock") 104 private boolean mTimerActive; 105 @GuardedBy("mLock") 106 private int mNextWakeupSec; 107 @GuardedBy("mLock") 108 private boolean mShutdownOnFinish; 109 @GuardedBy("mLock") 110 private boolean mShutdownOnNextSuspend; 111 @GuardedBy("mLock") 112 private boolean mIsBooting = true; 113 @GuardedBy("mLock") 114 private boolean mIsResuming; 115 @GuardedBy("mLock") 116 private boolean mRebootAfterGarageMode; 117 private final boolean mDisableUserSwitchDuringResume; 118 private final CarUserManagerHelper mCarUserManagerHelper; 119 private final UserManager mUserManager; // CarUserManagerHelper is deprecated... 120 private final String mNewGuestName; 121 122 // TODO: Make this OEM configurable. 123 private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000; 124 private static final int SHUTDOWN_EXTEND_MAX_MS = 5000; 125 126 // maxGarageModeRunningDurationInSecs should be equal or greater than this. 15 min for now. 127 private static final int MIN_MAX_GARAGE_MODE_DURATION_MS = 15 * 60 * 1000; 128 129 private static int sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS; 130 131 // in secs 132 private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE = 133 "android.car.garagemodeduration"; 134 135 private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> { 136 /** 137 * Old version of {@link #onCallbackDied(E, Object)} that 138 * does not provide a cookie. 139 */ 140 @Override onCallbackDied(ICarPowerStateListener listener)141 public void onCallbackDied(ICarPowerStateListener listener) { 142 Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder()); 143 CarPowerManagementService.this.doUnregisterListener(listener); 144 } 145 } 146 CarPowerManagementService(Context context, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper)147 public CarPowerManagementService(Context context, PowerHalService powerHal, 148 SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper) { 149 this(context, context.getResources(), powerHal, systemInterface, carUserManagerHelper, 150 UserManager.get(context), context.getString(R.string.default_guest_name)); 151 } 152 153 @VisibleForTesting CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper, UserManager userManager, String newGuestName)154 CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal, 155 SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper, 156 UserManager userManager, String newGuestName) { 157 mContext = context; 158 mHal = powerHal; 159 mSystemInterface = systemInterface; 160 mCarUserManagerHelper = carUserManagerHelper; 161 mUserManager = userManager; 162 mDisableUserSwitchDuringResume = resources 163 .getBoolean(R.bool.config_disableUserSwitchDuringResume); 164 sShutdownPrepareTimeMs = resources.getInteger( 165 R.integer.maxGarageModeRunningDurationInSecs) * 1000; 166 if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) { 167 Log.w(CarLog.TAG_POWER, 168 "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:" 169 + sShutdownPrepareTimeMs + "(ms) while should exceed:" 170 + MIN_MAX_GARAGE_MODE_DURATION_MS + "(ms), Ignore resource."); 171 sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS; 172 } 173 mNewGuestName = newGuestName; 174 } 175 176 @VisibleForTesting setShutdownPrepareTimeout(int timeoutMs)177 protected static void setShutdownPrepareTimeout(int timeoutMs) { 178 // Override the timeout to keep testing time short 179 if (timeoutMs < SHUTDOWN_EXTEND_MAX_MS) { 180 sShutdownPrepareTimeMs = SHUTDOWN_EXTEND_MAX_MS; 181 } else { 182 sShutdownPrepareTimeMs = timeoutMs; 183 } 184 } 185 186 @VisibleForTesting getHandlerThread()187 protected HandlerThread getHandlerThread() { 188 synchronized (mLock) { 189 return mHandlerThread; 190 } 191 } 192 193 @Override init()194 public void init() { 195 synchronized (mLock) { 196 mHandlerThread = new HandlerThread(CarLog.TAG_POWER); 197 mHandlerThread.start(); 198 mHandler = new PowerHandler(mHandlerThread.getLooper()); 199 } 200 201 mHal.setListener(this); 202 if (mHal.isPowerStateSupported()) { 203 // Initialize CPMS in WAIT_FOR_VHAL state 204 onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, CarPowerStateListener.WAIT_FOR_VHAL); 205 } else { 206 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet."); 207 onApPowerStateChange(CpmsState.ON, CarPowerStateListener.ON); 208 } 209 mSystemInterface.startDisplayStateMonitoring(this); 210 } 211 212 @Override release()213 public void release() { 214 HandlerThread handlerThread; 215 synchronized (mLock) { 216 releaseTimerLocked(); 217 mCurrentState = null; 218 mHandler.cancelAll(); 219 handlerThread = mHandlerThread; 220 mListenersWeAreWaitingFor.clear(); 221 } 222 handlerThread.quitSafely(); 223 try { 224 handlerThread.join(1000); 225 } catch (InterruptedException e) { 226 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join."); 227 } 228 mSystemInterface.stopDisplayStateMonitoring(); 229 mPowerManagerListeners.kill(); 230 mSystemInterface.releaseAllWakeLocks(); 231 } 232 233 @Override dump(PrintWriter writer)234 public void dump(PrintWriter writer) { 235 writer.println("*PowerManagementService*"); 236 writer.print("mCurrentState:" + mCurrentState); 237 writer.print(",mProcessingStartTime:" + mProcessingStartTime); 238 writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime); 239 writer.print(",mNextWakeupSec:" + mNextWakeupSec); 240 writer.print(",mShutdownOnNextSuspend:" + mShutdownOnNextSuspend); 241 writer.print(",mShutdownOnFinish:" + mShutdownOnFinish); 242 writer.print(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs); 243 writer.print(",mDisableUserSwitchDuringResume:" + mDisableUserSwitchDuringResume); 244 writer.println(",mRebootAfterGarageMode:" + mRebootAfterGarageMode); 245 writer.print("mNewGuestName: "); writer.println(mNewGuestName); 246 } 247 248 @Override onApPowerStateChange(PowerState state)249 public void onApPowerStateChange(PowerState state) { 250 PowerHandler handler; 251 synchronized (mLock) { 252 mPendingPowerStates.addFirst(new CpmsState(state)); 253 handler = mHandler; 254 } 255 handler.handlePowerStateChange(); 256 } 257 258 @VisibleForTesting setStateForTesting(boolean isBooting, boolean isResuming)259 void setStateForTesting(boolean isBooting, boolean isResuming) { 260 synchronized (mLock) { 261 Log.d(CarLog.TAG_POWER, "setStateForTesting():" 262 + " booting(" + mIsBooting + ">" + isBooting + ")" 263 + " resuming(" + mIsResuming + ">" + isResuming + ")"); 264 mIsBooting = isBooting; 265 mIsResuming = isResuming; 266 } 267 } 268 269 /** 270 * Initiate state change from CPMS directly. 271 */ onApPowerStateChange(int apState, int carPowerStateListenerState)272 private void onApPowerStateChange(int apState, int carPowerStateListenerState) { 273 CpmsState newState = new CpmsState(apState, carPowerStateListenerState); 274 PowerHandler handler; 275 synchronized (mLock) { 276 mPendingPowerStates.addFirst(newState); 277 handler = mHandler; 278 } 279 handler.handlePowerStateChange(); 280 } 281 doHandlePowerStateChange()282 private void doHandlePowerStateChange() { 283 CpmsState state; 284 PowerHandler handler; 285 synchronized (mLock) { 286 state = mPendingPowerStates.peekFirst(); 287 mPendingPowerStates.clear(); 288 if (state == null) { 289 return; 290 } 291 Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name()); 292 if (!needPowerStateChangeLocked(state)) { 293 Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed"); 294 return; 295 } 296 // now real power change happens. Whatever was queued before should be all cancelled. 297 releaseTimerLocked(); 298 handler = mHandler; 299 } 300 handler.cancelProcessingComplete(); 301 Log.i(CarLog.TAG_POWER, "setCurrentState " + state.toString()); 302 CarStatsLog.logPowerState(state.mState); 303 mCurrentState = state; 304 switch (state.mState) { 305 case CpmsState.WAIT_FOR_VHAL: 306 handleWaitForVhal(state); 307 break; 308 case CpmsState.ON: 309 handleOn(); 310 break; 311 case CpmsState.SHUTDOWN_PREPARE: 312 handleShutdownPrepare(state); 313 break; 314 case CpmsState.SIMULATE_SLEEP: 315 simulateShutdownPrepare(); 316 break; 317 case CpmsState.WAIT_FOR_FINISH: 318 handleWaitForFinish(state); 319 break; 320 case CpmsState.SUSPEND: 321 // Received FINISH from VHAL 322 handleFinish(); 323 break; 324 default: 325 // Illegal state 326 // TODO: Throw exception? 327 break; 328 } 329 } 330 handleWaitForVhal(CpmsState state)331 private void handleWaitForVhal(CpmsState state) { 332 int carPowerStateListenerState = state.mCarPowerStateListenerState; 333 sendPowerManagerEvent(carPowerStateListenerState); 334 // Inspect CarPowerStateListenerState to decide which message to send via VHAL 335 switch (carPowerStateListenerState) { 336 case CarPowerStateListener.WAIT_FOR_VHAL: 337 mHal.sendWaitForVhal(); 338 break; 339 case CarPowerStateListener.SHUTDOWN_CANCELLED: 340 mShutdownOnNextSuspend = false; // This cancels the "NextSuspend" 341 mHal.sendShutdownCancel(); 342 break; 343 case CarPowerStateListener.SUSPEND_EXIT: 344 mHal.sendSleepExit(); 345 break; 346 } 347 } 348 updateCarUserNoticeServiceIfNecessary()349 private void updateCarUserNoticeServiceIfNecessary() { 350 try { 351 int currentUserId = ActivityManager.getCurrentUser(); 352 UserInfo currentUserInfo = mUserManager.getUserInfo(currentUserId); 353 CarUserNoticeService carUserNoticeService = 354 CarLocalServices.getService(CarUserNoticeService.class); 355 if (currentUserInfo != null && currentUserInfo.isGuest() 356 && carUserNoticeService != null) { 357 Log.i(CarLog.TAG_POWER, 358 "Car user notice service will ignore all messages before user switch."); 359 Intent intent = new Intent(); 360 intent.setComponent(new ComponentName(mContext.getPackageName(), 361 ContinuousBlankActivity.class.getName())); 362 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 363 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 364 carUserNoticeService.ignoreUserNotice(currentUserId); 365 } 366 } catch (Exception e) { 367 Log.w(CarLog.TAG_POWER, "Cannot ignore user notice for current user", e); 368 } 369 } 370 handleOn()371 private void handleOn() { 372 // If current user is a Guest User, we want to inform CarUserNoticeService not to show 373 // notice for current user, and show user notice only for the target user. 374 updateCarUserNoticeServiceIfNecessary(); 375 376 // Some OEMs have their own user-switching logic, which may not be coordinated with this 377 // code. To avoid contention, we don't switch users when we coming alive. The OEM's code 378 // should do the switch. 379 boolean allowUserSwitch = true; 380 synchronized (mLock) { 381 if (mIsBooting) { 382 // The system is booting, so don't switch users 383 allowUserSwitch = false; 384 mIsBooting = false; 385 mIsResuming = false; 386 Log.i(CarLog.TAG_POWER, "User switch disallowed while booting"); 387 } else { 388 // The system is resuming after a suspension. Optionally disable user switching. 389 allowUserSwitch = !mDisableUserSwitchDuringResume; 390 mIsBooting = false; 391 mIsResuming = false; 392 if (!allowUserSwitch) { 393 Log.i(CarLog.TAG_POWER, "User switch disallowed while resuming"); 394 } 395 } 396 } 397 398 mSystemInterface.setDisplayState(true); 399 sendPowerManagerEvent(CarPowerStateListener.ON); 400 mHal.sendOn(); 401 402 try { 403 switchUserOnResumeIfNecessary(allowUserSwitch); 404 } catch (Exception e) { 405 Log.e(CarLog.TAG_POWER, "Could not switch user on resume: " + e); 406 } 407 } 408 switchUserOnResumeIfNecessary(boolean allowSwitching)409 private void switchUserOnResumeIfNecessary(boolean allowSwitching) { 410 int targetUserId = mCarUserManagerHelper.getInitialUser(); 411 if (targetUserId == UserHandle.USER_SYSTEM) { 412 // API explicitly say it doesn't return USER_SYSTEM 413 Log.wtf(CarLog.TAG_POWER, "getInitialUser() returned system user"); 414 return; 415 } 416 int currentUserId = ActivityManager.getCurrentUser(); 417 UserInfo targetUserInfo = mUserManager.getUserInfo(targetUserId); 418 boolean isTargetPersistent = !targetUserInfo.isEphemeral(); 419 boolean isTargetGuest = targetUserInfo.isGuest(); 420 Log.d(CarLog.TAG_POWER, "getTargetUserId(): current=" + currentUserId 421 + ", target=" + targetUserInfo.toFullString() 422 + ", isTargetPersistent=" + isTargetPersistent + ", isTargetGuest=" + isTargetGuest 423 + ", allowSwitching: " + allowSwitching); 424 425 if (isTargetPersistent && !isTargetGuest) { 426 if (!allowSwitching) { 427 Log.d(CarLog.TAG_POWER, "Not switching to " + targetUserId 428 + " because it's not allowed"); 429 return; 430 } 431 if (currentUserId == targetUserId) { 432 Log.v(CarLog.TAG_POWER, "no need to switch to (same user) " + currentUserId); 433 return; 434 } 435 // All good - switch to the requested user 436 switchToUser(currentUserId, targetUserId, /* reason= */ null); 437 return; 438 } 439 440 if (!isTargetGuest) { 441 // Shouldn't happen (unless OEM is explicitly creating ephemeral users, which 442 // doesn't make much sense), but it doesn't hurt to log... 443 Log.w(CarLog.TAG_POWER, "target user is ephemeral but not a guest: " 444 + targetUserInfo.toFullString()); 445 if (allowSwitching) { 446 switchToUser(currentUserId, targetUserId, /* reason= */ null); 447 } 448 return; 449 } else if (isTargetPersistent) { 450 // TODO(b/146380030): decide whether we should delete it or not 451 // Shouldn't happen neither, but it's not a big deal (guest will be replaced below 452 // anyway), but it's worth logging as well... 453 Log.w(CarLog.TAG_POWER, "target user is a non-ephemeral guest: " 454 + targetUserInfo.toFullString()); 455 } 456 457 // At this point, target user is a guest - we cannot resume into an ephemeral guest for 458 // privacy reasons, so we need to create a new guest and switch to it (even if the OEM 459 // doesn't allow switching) 460 461 462 boolean marked = mUserManager.markGuestForDeletion(targetUserId); 463 if (!marked) { 464 Log.w(CarLog.TAG_POWER, "Could not mark guest user " + targetUserId + " for deletion"); 465 return; 466 } 467 468 UserInfo newGuest = mUserManager.createGuest(mContext, mNewGuestName); 469 470 if (newGuest != null) { 471 switchToUser(currentUserId, newGuest.id, "Created new guest"); 472 Log.d(CarLog.TAG_POWER, "Removing previous guest " + targetUserId); 473 mUserManager.removeUser(targetUserId); 474 } else { 475 Log.wtf(CarLog.TAG_POWER, "Could not create new guest"); 476 // TODO(b/146380030): decide whether we should switch to SYSTEM 477 } 478 } 479 switchToUser(@serIdInt int fromUser, @UserIdInt int toUser, @Nullable String reason)480 private void switchToUser(@UserIdInt int fromUser, @UserIdInt int toUser, 481 @Nullable String reason) { 482 StringBuilder message = new StringBuilder(); 483 if (reason == null) { 484 message.append("Desired user changed"); 485 } else { 486 message.append(reason); 487 } 488 message.append(", switching from ").append(fromUser).append(" to ").append(toUser); 489 Log.i(CarLog.TAG_POWER, message.toString()); 490 mCarUserManagerHelper.switchToUserId(toUser); 491 } 492 getFirstSwitchableUser()493 private int getFirstSwitchableUser() { 494 List<UserInfo> allUsers = mUserManager.getUsers(); 495 for (UserInfo user : allUsers) { 496 if (user.id != UserHandle.USER_SYSTEM) { 497 return user.id; 498 } 499 } 500 Log.wtf(CarLog.TAG_POWER, "no switchable user: " + allUsers); 501 return UserHandle.USER_NULL; 502 } 503 handleShutdownPrepare(CpmsState newState)504 private void handleShutdownPrepare(CpmsState newState) { 505 mSystemInterface.setDisplayState(false); 506 // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it. 507 synchronized (mLock) { 508 mShutdownOnFinish = mShutdownOnNextSuspend 509 || !mHal.isDeepSleepAllowed() 510 || !mSystemInterface.isSystemSupportingDeepSleep() 511 || !newState.mCanSleep; 512 } 513 if (newState.mCanPostpone) { 514 Log.i(CarLog.TAG_POWER, "starting shutdown prepare"); 515 sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE); 516 mHal.sendShutdownPrepare(); 517 doHandlePreprocessing(); 518 } else { 519 Log.i(CarLog.TAG_POWER, "starting shutdown immediately"); 520 synchronized (mLock) { 521 releaseTimerLocked(); 522 } 523 // Notify hal that we are shutting down and since it is immediate, don't schedule next 524 // wake up 525 mHal.sendShutdownStart(0); 526 // shutdown HU 527 mSystemInterface.shutdown(); 528 } 529 } 530 531 // Simulate system shutdown to Deep Sleep simulateShutdownPrepare()532 private void simulateShutdownPrepare() { 533 mSystemInterface.setDisplayState(false); 534 Log.i(CarLog.TAG_POWER, "starting shutdown prepare"); 535 sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE); 536 mHal.sendShutdownPrepare(); 537 doHandlePreprocessing(); 538 } 539 handleWaitForFinish(CpmsState state)540 private void handleWaitForFinish(CpmsState state) { 541 sendPowerManagerEvent(state.mCarPowerStateListenerState); 542 int wakeupSec; 543 synchronized (mLock) { 544 wakeupSec = mNextWakeupSec; 545 } 546 switch (state.mCarPowerStateListenerState) { 547 case CarPowerStateListener.SUSPEND_ENTER: 548 mHal.sendSleepEntry(wakeupSec); 549 break; 550 case CarPowerStateListener.SHUTDOWN_ENTER: 551 mHal.sendShutdownStart(wakeupSec); 552 break; 553 } 554 } 555 handleFinish()556 private void handleFinish() { 557 boolean simulatedMode; 558 synchronized (mSimulationWaitObject) { 559 simulatedMode = mInSimulatedDeepSleepMode; 560 } 561 boolean mustShutDown; 562 boolean forceReboot; 563 synchronized (mLock) { 564 mustShutDown = mShutdownOnFinish && !simulatedMode; 565 forceReboot = mRebootAfterGarageMode; 566 mRebootAfterGarageMode = false; 567 } 568 if (forceReboot) { 569 PowerManager powerManager = mContext.getSystemService(PowerManager.class); 570 if (powerManager == null) { 571 Log.wtf(CarLog.TAG_POWER, "No PowerManager. Cannot reboot."); 572 } else { 573 Log.i(CarLog.TAG_POWER, "GarageMode has completed. Forcing reboot."); 574 powerManager.reboot("GarageModeReboot"); 575 throw new AssertionError("Should not return from PowerManager.reboot()"); 576 } 577 } 578 if (mustShutDown) { 579 // shutdown HU 580 mSystemInterface.shutdown(); 581 } else { 582 doHandleDeepSleep(simulatedMode); 583 } 584 mShutdownOnNextSuspend = false; 585 } 586 587 @GuardedBy("mLock") releaseTimerLocked()588 private void releaseTimerLocked() { 589 if (mTimer != null) { 590 mTimer.cancel(); 591 } 592 mTimer = null; 593 mTimerActive = false; 594 } 595 doHandlePreprocessing()596 private void doHandlePreprocessing() { 597 int pollingCount = (sShutdownPrepareTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1; 598 if (Build.IS_USERDEBUG || Build.IS_ENG) { 599 int shutdownPrepareTimeOverrideInSecs = 600 SystemProperties.getInt(PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE, -1); 601 if (shutdownPrepareTimeOverrideInSecs >= 0) { 602 pollingCount = 603 (shutdownPrepareTimeOverrideInSecs * 1000 / SHUTDOWN_POLLING_INTERVAL_MS) 604 + 1; 605 Log.i(CarLog.TAG_POWER, 606 "Garage mode duration overridden secs:" 607 + shutdownPrepareTimeOverrideInSecs); 608 } 609 } 610 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: " 611 + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount); 612 synchronized (mLock) { 613 mProcessingStartTime = SystemClock.elapsedRealtime(); 614 releaseTimerLocked(); 615 mTimer = new Timer(); 616 mTimerActive = true; 617 mTimer.scheduleAtFixedRate( 618 new ShutdownProcessingTimerTask(pollingCount), 619 0 /*delay*/, 620 SHUTDOWN_POLLING_INTERVAL_MS); 621 } 622 } 623 sendPowerManagerEvent(int newState)624 private void sendPowerManagerEvent(int newState) { 625 // Broadcast to the listeners that do not signal completion 626 notifyListeners(mPowerManagerListeners, newState); 627 628 // SHUTDOWN_PREPARE is the only state where we need 629 // to maintain callbacks from listener components. 630 boolean allowCompletion = (newState == CarPowerStateListener.SHUTDOWN_PREPARE); 631 632 // Fully populate mListenersWeAreWaitingFor before calling any onStateChanged() 633 // for the listeners that signal completion. 634 // Otherwise, if the first listener calls finish() synchronously, we will 635 // see the list go empty and we will think that we are done. 636 boolean haveSomeCompleters = false; 637 PowerManagerCallbackList completingListeners = new PowerManagerCallbackList(); 638 synchronized (mLock) { 639 mListenersWeAreWaitingFor.clear(); 640 int idx = mPowerManagerListenersWithCompletion.beginBroadcast(); 641 while (idx-- > 0) { 642 ICarPowerStateListener listener = 643 mPowerManagerListenersWithCompletion.getBroadcastItem(idx); 644 completingListeners.register(listener); 645 if (allowCompletion) { 646 mListenersWeAreWaitingFor.add(listener.asBinder()); 647 haveSomeCompleters = true; 648 } 649 } 650 mPowerManagerListenersWithCompletion.finishBroadcast(); 651 } 652 // Broadcast to the listeners that DO signal completion 653 notifyListeners(completingListeners, newState); 654 655 if (allowCompletion && !haveSomeCompleters) { 656 // No jobs need to signal completion. So we are now complete. 657 signalComplete(); 658 } 659 } 660 notifyListeners(PowerManagerCallbackList listenerList, int newState)661 private void notifyListeners(PowerManagerCallbackList listenerList, int newState) { 662 int idx = listenerList.beginBroadcast(); 663 while (idx-- > 0) { 664 ICarPowerStateListener listener = listenerList.getBroadcastItem(idx); 665 try { 666 listener.onStateChanged(newState); 667 } catch (RemoteException e) { 668 // It's likely the connection snapped. Let binder death handle the situation. 669 Log.e(CarLog.TAG_POWER, "onStateChanged() call failed", e); 670 } 671 } 672 listenerList.finishBroadcast(); 673 } 674 doHandleDeepSleep(boolean simulatedMode)675 private void doHandleDeepSleep(boolean simulatedMode) { 676 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call 677 // enterDeepSleep should force sleep entry even if wake lock is kept. 678 mSystemInterface.switchToPartialWakeLock(); 679 PowerHandler handler; 680 synchronized (mLock) { 681 handler = mHandler; 682 } 683 handler.cancelProcessingComplete(); 684 synchronized (mLock) { 685 mLastSleepEntryTime = SystemClock.elapsedRealtime(); 686 } 687 int nextListenerState; 688 if (simulatedMode) { 689 simulateSleepByWaiting(); 690 nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED; 691 } else { 692 boolean sleepSucceeded = mSystemInterface.enterDeepSleep(); 693 if (!sleepSucceeded) { 694 // Suspend failed! VHAL should transition CPMS to shutdown. 695 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down."); 696 mSystemInterface.shutdown(); 697 return; 698 } 699 nextListenerState = CarPowerStateListener.SUSPEND_EXIT; 700 } 701 // On resume, reset nextWakeup time. If not set again, system will suspend/shutdown forever. 702 synchronized (mLock) { 703 mIsResuming = true; 704 mNextWakeupSec = 0; 705 } 706 Log.i(CarLog.TAG_POWER, "Resuming after suspending"); 707 mSystemInterface.refreshDisplayBrightness(); 708 onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState); 709 } 710 needPowerStateChangeLocked(CpmsState newState)711 private boolean needPowerStateChangeLocked(CpmsState newState) { 712 if (newState == null) { 713 return false; 714 } else if (mCurrentState == null) { 715 return true; 716 } else if (mCurrentState.equals(newState)) { 717 return false; 718 } 719 720 // The following switch/case enforces the allowed state transitions. 721 switch (mCurrentState.mState) { 722 case CpmsState.WAIT_FOR_VHAL: 723 return (newState.mState == CpmsState.ON) 724 || (newState.mState == CpmsState.SHUTDOWN_PREPARE); 725 case CpmsState.SUSPEND: 726 return newState.mState == CpmsState.WAIT_FOR_VHAL; 727 case CpmsState.ON: 728 return (newState.mState == CpmsState.SHUTDOWN_PREPARE) 729 || (newState.mState == CpmsState.SIMULATE_SLEEP); 730 case CpmsState.SHUTDOWN_PREPARE: 731 // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it. 732 return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone) 733 || (newState.mState == CpmsState.WAIT_FOR_FINISH) 734 || (newState.mState == CpmsState.WAIT_FOR_VHAL); 735 case CpmsState.SIMULATE_SLEEP: 736 return true; 737 case CpmsState.WAIT_FOR_FINISH: 738 return newState.mState == CpmsState.SUSPEND; 739 default: 740 Log.e(CarLog.TAG_POWER, "Unhandled state transition: currentState=" 741 + mCurrentState.name() + ", newState=" + newState.name()); 742 return false; 743 } 744 } 745 doHandleProcessingComplete()746 private void doHandleProcessingComplete() { 747 int listenerState; 748 synchronized (mLock) { 749 releaseTimerLocked(); 750 if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) { 751 // entered sleep after processing start. So this could be duplicate request. 752 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore"); 753 return; 754 } 755 listenerState = mShutdownOnFinish 756 ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER; 757 } 758 onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState); 759 } 760 761 @Override onDisplayBrightnessChange(int brightness)762 public void onDisplayBrightnessChange(int brightness) { 763 PowerHandler handler; 764 synchronized (mLock) { 765 handler = mHandler; 766 } 767 handler.handleDisplayBrightnessChange(brightness); 768 } 769 doHandleDisplayBrightnessChange(int brightness)770 private void doHandleDisplayBrightnessChange(int brightness) { 771 mSystemInterface.setDisplayBrightness(brightness); 772 } 773 doHandleMainDisplayStateChange(boolean on)774 private void doHandleMainDisplayStateChange(boolean on) { 775 Log.w(CarLog.TAG_POWER, "Unimplemented: doHandleMainDisplayStateChange() - on = " + on); 776 } 777 handleMainDisplayChanged(boolean on)778 public void handleMainDisplayChanged(boolean on) { 779 PowerHandler handler; 780 synchronized (mLock) { 781 handler = mHandler; 782 } 783 handler.handleMainDisplayStateChange(on); 784 } 785 786 /** 787 * Send display brightness to VHAL. 788 * @param brightness value 0-100% 789 */ sendDisplayBrightness(int brightness)790 public void sendDisplayBrightness(int brightness) { 791 mHal.sendDisplayBrightness(brightness); 792 } 793 794 /** 795 * Get the PowerHandler that we use to change power states 796 */ getHandler()797 public Handler getHandler() { 798 synchronized (mLock) { 799 return mHandler; 800 } 801 } 802 803 // Binder interface for general use. 804 // The listener is not required (or allowed) to call finished(). 805 @Override registerListener(ICarPowerStateListener listener)806 public void registerListener(ICarPowerStateListener listener) { 807 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 808 mPowerManagerListeners.register(listener); 809 } 810 811 // Binder interface for Car services only. 812 // After the listener completes its processing, it must call finished(). 813 @Override registerListenerWithCompletion(ICarPowerStateListener listener)814 public void registerListenerWithCompletion(ICarPowerStateListener listener) { 815 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 816 ICarImpl.assertCallingFromSystemProcessOrSelf(); 817 818 mPowerManagerListenersWithCompletion.register(listener); 819 // TODO: Need to send current state to newly registered listener? If so, need to handle 820 // completion for SHUTDOWN_PREPARE state 821 } 822 823 @Override unregisterListener(ICarPowerStateListener listener)824 public void unregisterListener(ICarPowerStateListener listener) { 825 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 826 doUnregisterListener(listener); 827 } 828 doUnregisterListener(ICarPowerStateListener listener)829 private void doUnregisterListener(ICarPowerStateListener listener) { 830 mPowerManagerListeners.unregister(listener); 831 boolean found = mPowerManagerListenersWithCompletion.unregister(listener); 832 if (found) { 833 // Remove this from the completion list (if it's there) 834 finishedImpl(listener.asBinder()); 835 } 836 } 837 838 @Override requestShutdownOnNextSuspend()839 public void requestShutdownOnNextSuspend() { 840 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 841 synchronized (mLock) { 842 mShutdownOnNextSuspend = true; 843 } 844 } 845 846 @Override finished(ICarPowerStateListener listener)847 public void finished(ICarPowerStateListener listener) { 848 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 849 ICarImpl.assertCallingFromSystemProcessOrSelf(); 850 finishedImpl(listener.asBinder()); 851 } 852 853 @Override scheduleNextWakeupTime(int seconds)854 public void scheduleNextWakeupTime(int seconds) { 855 if (seconds < 0) { 856 Log.w(CarLog.TAG_POWER, "Next wake up time is negative. Ignoring!"); 857 return; 858 } 859 boolean timedWakeupAllowed = mHal.isTimedWakeupAllowed(); 860 synchronized (mLock) { 861 if (!timedWakeupAllowed) { 862 Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping"); 863 mNextWakeupSec = 0; 864 return; 865 } 866 if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) { 867 // The new value is sooner than the old value. Take the new value. 868 mNextWakeupSec = seconds; 869 } else { 870 Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter " 871 + "scheduled time"); 872 } 873 } 874 } 875 finishedImpl(IBinder binder)876 private void finishedImpl(IBinder binder) { 877 boolean allAreComplete = false; 878 synchronized (mLock) { 879 boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder); 880 allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty(); 881 } 882 if (allAreComplete) { 883 signalComplete(); 884 } 885 } 886 signalComplete()887 private void signalComplete() { 888 if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE 889 || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) { 890 PowerHandler powerHandler; 891 // All apps are ready to shutdown/suspend. 892 synchronized (mLock) { 893 if (!mShutdownOnFinish) { 894 if (mLastSleepEntryTime > mProcessingStartTime 895 && mLastSleepEntryTime < SystemClock.elapsedRealtime()) { 896 Log.i(CarLog.TAG_POWER, "signalComplete: Already slept!"); 897 return; 898 } 899 } 900 powerHandler = mHandler; 901 } 902 Log.i(CarLog.TAG_POWER, "Apps are finished, call handleProcessingComplete()"); 903 powerHandler.handleProcessingComplete(); 904 } 905 } 906 907 private class PowerHandler extends Handler { 908 private final int MSG_POWER_STATE_CHANGE = 0; 909 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1; 910 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2; 911 private final int MSG_PROCESSING_COMPLETE = 3; 912 913 // Do not handle this immediately but with some delay as there can be a race between 914 // display off due to rear view camera and delivery to here. 915 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500; 916 PowerHandler(Looper looper)917 private PowerHandler(Looper looper) { 918 super(looper); 919 } 920 handlePowerStateChange()921 private void handlePowerStateChange() { 922 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE); 923 sendMessage(msg); 924 } 925 handleDisplayBrightnessChange(int brightness)926 private void handleDisplayBrightnessChange(int brightness) { 927 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0); 928 sendMessage(msg); 929 } 930 handleMainDisplayStateChange(boolean on)931 private void handleMainDisplayStateChange(boolean on) { 932 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 933 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on)); 934 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS); 935 } 936 handleProcessingComplete()937 private void handleProcessingComplete() { 938 removeMessages(MSG_PROCESSING_COMPLETE); 939 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE); 940 sendMessage(msg); 941 } 942 cancelProcessingComplete()943 private void cancelProcessingComplete() { 944 removeMessages(MSG_PROCESSING_COMPLETE); 945 } 946 cancelAll()947 private void cancelAll() { 948 removeMessages(MSG_POWER_STATE_CHANGE); 949 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE); 950 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 951 removeMessages(MSG_PROCESSING_COMPLETE); 952 } 953 954 @Override handleMessage(Message msg)955 public void handleMessage(Message msg) { 956 switch (msg.what) { 957 case MSG_POWER_STATE_CHANGE: 958 doHandlePowerStateChange(); 959 break; 960 case MSG_DISPLAY_BRIGHTNESS_CHANGE: 961 doHandleDisplayBrightnessChange(msg.arg1); 962 break; 963 case MSG_MAIN_DISPLAY_STATE_CHANGE: 964 doHandleMainDisplayStateChange((Boolean) msg.obj); 965 break; 966 case MSG_PROCESSING_COMPLETE: 967 doHandleProcessingComplete(); 968 break; 969 } 970 } 971 } 972 973 private class ShutdownProcessingTimerTask extends TimerTask { 974 private final int mExpirationCount; 975 private int mCurrentCount; 976 ShutdownProcessingTimerTask(int expirationCount)977 private ShutdownProcessingTimerTask(int expirationCount) { 978 mExpirationCount = expirationCount; 979 mCurrentCount = 0; 980 } 981 982 @Override run()983 public void run() { 984 synchronized (mLock) { 985 if (!mTimerActive) { 986 // Ignore timer expiration since we got cancelled 987 return; 988 } 989 mCurrentCount++; 990 if (mCurrentCount > mExpirationCount) { 991 PowerHandler handler; 992 releaseTimerLocked(); 993 handler = mHandler; 994 handler.handleProcessingComplete(); 995 } else { 996 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS); 997 } 998 } 999 } 1000 } 1001 1002 private static class CpmsState { 1003 // NOTE: When modifying states below, make sure to update CarPowerStateChanged.State in 1004 // frameworks/base/cmds/statsd/src/atoms.proto also. 1005 public static final int WAIT_FOR_VHAL = 0; 1006 public static final int ON = 1; 1007 public static final int SHUTDOWN_PREPARE = 2; 1008 public static final int WAIT_FOR_FINISH = 3; 1009 public static final int SUSPEND = 4; 1010 public static final int SIMULATE_SLEEP = 5; 1011 1012 /* Config values from AP_POWER_STATE_REQ */ 1013 public final boolean mCanPostpone; 1014 public final boolean mCanSleep; 1015 /* Message sent to CarPowerStateListener in response to this state */ 1016 public final int mCarPowerStateListenerState; 1017 /* One of the above state variables */ 1018 public final int mState; 1019 1020 /** 1021 * This constructor takes a PowerHalService.PowerState object and creates the corresponding 1022 * CPMS state from it. 1023 */ CpmsState(PowerState halPowerState)1024 CpmsState(PowerState halPowerState) { 1025 switch (halPowerState.mState) { 1026 case VehicleApPowerStateReq.ON: 1027 this.mCanPostpone = false; 1028 this.mCanSleep = false; 1029 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(ON); 1030 this.mState = ON; 1031 break; 1032 case VehicleApPowerStateReq.SHUTDOWN_PREPARE: 1033 this.mCanPostpone = halPowerState.canPostponeShutdown(); 1034 this.mCanSleep = halPowerState.canEnterDeepSleep(); 1035 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState( 1036 SHUTDOWN_PREPARE); 1037 this.mState = SHUTDOWN_PREPARE; 1038 break; 1039 case VehicleApPowerStateReq.CANCEL_SHUTDOWN: 1040 this.mCanPostpone = false; 1041 this.mCanSleep = false; 1042 this.mCarPowerStateListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED; 1043 this.mState = WAIT_FOR_VHAL; 1044 break; 1045 case VehicleApPowerStateReq.FINISHED: 1046 this.mCanPostpone = false; 1047 this.mCanSleep = false; 1048 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(SUSPEND); 1049 this.mState = SUSPEND; 1050 break; 1051 default: 1052 // Illegal state from PowerState. Throw an exception? 1053 this.mCanPostpone = false; 1054 this.mCanSleep = false; 1055 this.mCarPowerStateListenerState = 0; 1056 this.mState = 0; 1057 break; 1058 } 1059 } 1060 CpmsState(int state)1061 CpmsState(int state) { 1062 this(state, cpmsStateToPowerStateListenerState(state)); 1063 } 1064 CpmsState(int state, int carPowerStateListenerState)1065 CpmsState(int state, int carPowerStateListenerState) { 1066 this.mCanPostpone = (state == SIMULATE_SLEEP); 1067 this.mCanSleep = (state == SIMULATE_SLEEP); 1068 this.mCarPowerStateListenerState = carPowerStateListenerState; 1069 this.mState = state; 1070 } 1071 name()1072 public String name() { 1073 String baseName; 1074 switch(mState) { 1075 case WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break; 1076 case ON: baseName = "ON"; break; 1077 case SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 1078 case WAIT_FOR_FINISH: baseName = "WAIT_FOR_FINISH"; break; 1079 case SUSPEND: baseName = "SUSPEND"; break; 1080 case SIMULATE_SLEEP: baseName = "SIMULATE_SLEEP"; break; 1081 default: baseName = "<unknown>"; break; 1082 } 1083 return baseName + "(" + mState + ")"; 1084 } 1085 cpmsStateToPowerStateListenerState(int state)1086 private static int cpmsStateToPowerStateListenerState(int state) { 1087 int powerStateListenerState = 0; 1088 1089 // Set the CarPowerStateListenerState based on current state 1090 switch (state) { 1091 case ON: 1092 powerStateListenerState = CarPowerStateListener.ON; 1093 break; 1094 case SHUTDOWN_PREPARE: 1095 powerStateListenerState = CarPowerStateListener.SHUTDOWN_PREPARE; 1096 break; 1097 case SUSPEND: 1098 powerStateListenerState = CarPowerStateListener.SUSPEND_ENTER; 1099 break; 1100 case WAIT_FOR_VHAL: 1101 case WAIT_FOR_FINISH: 1102 default: 1103 // Illegal state for this constructor. Throw an exception? 1104 break; 1105 } 1106 return powerStateListenerState; 1107 } 1108 1109 @Override equals(Object o)1110 public boolean equals(Object o) { 1111 if (this == o) { 1112 return true; 1113 } 1114 if (!(o instanceof CpmsState)) { 1115 return false; 1116 } 1117 CpmsState that = (CpmsState) o; 1118 return this.mState == that.mState 1119 && this.mCanSleep == that.mCanSleep 1120 && this.mCanPostpone == that.mCanPostpone 1121 && this.mCarPowerStateListenerState == that.mCarPowerStateListenerState; 1122 } 1123 1124 @Override toString()1125 public String toString() { 1126 return "CpmsState canSleep:" + mCanSleep + ", canPostpone=" + mCanPostpone 1127 + ", carPowerStateListenerState=" + mCarPowerStateListenerState 1128 + ", CpmsState=" + this.name(); 1129 } 1130 } 1131 1132 /** 1133 * Resume after a manually-invoked suspend. 1134 * Invoked using "adb shell dumpsys activity service com.android.car resume". 1135 */ forceSimulatedResume()1136 public void forceSimulatedResume() { 1137 PowerHandler handler; 1138 synchronized (this) { 1139 // Cancel Garage Mode in case it's running 1140 mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL, 1141 CarPowerStateListener.SHUTDOWN_CANCELLED)); 1142 handler = mHandler; 1143 } 1144 handler.handlePowerStateChange(); 1145 1146 synchronized (mSimulationWaitObject) { 1147 mWakeFromSimulatedSleep = true; 1148 mSimulationWaitObject.notify(); 1149 } 1150 } 1151 1152 /** 1153 * Manually enter simulated suspend (Deep Sleep) mode, trigging Garage mode. 1154 * If the parameter is 'true', reboot the system when Garage Mode completes. 1155 * 1156 * Invoked using "adb shell dumpsys activity service com.android.car suspend" or 1157 * "adb shell dumpsys activity service com.android.car garage-mode reboot". 1158 * This is similar to 'onApPowerStateChange()' except that it needs to create a CpmsState 1159 * that is not directly derived from a VehicleApPowerStateReq. 1160 */ 1161 @VisibleForTesting forceSuspendAndMaybeReboot(boolean shouldReboot)1162 void forceSuspendAndMaybeReboot(boolean shouldReboot) { 1163 synchronized (mSimulationWaitObject) { 1164 mInSimulatedDeepSleepMode = true; 1165 mWakeFromSimulatedSleep = false; 1166 } 1167 PowerHandler handler; 1168 synchronized (mLock) { 1169 mRebootAfterGarageMode = shouldReboot; 1170 mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP, 1171 CarPowerStateListener.SHUTDOWN_PREPARE)); 1172 handler = mHandler; 1173 } 1174 handler.handlePowerStateChange(); 1175 } 1176 1177 // In a real Deep Sleep, the hardware removes power from the CPU (but retains power 1178 // on the RAM). This puts the processor to sleep. Upon some external signal, power 1179 // is re-applied to the CPU, and processing resumes right where it left off. 1180 // We simulate this behavior by calling wait(). 1181 // We continue from wait() when forceSimulatedResume() is called. simulateSleepByWaiting()1182 private void simulateSleepByWaiting() { 1183 Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by waiting"); 1184 synchronized (mSimulationWaitObject) { 1185 while (!mWakeFromSimulatedSleep) { 1186 try { 1187 mSimulationWaitObject.wait(); 1188 } catch (InterruptedException ignored) { 1189 Thread.currentThread().interrupt(); // Restore interrupted status 1190 } 1191 } 1192 mInSimulatedDeepSleepMode = false; 1193 } 1194 Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation"); 1195 } 1196 } 1197