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.car.Car; 19 import android.car.hardware.power.CarPowerManager.CarPowerStateListener; 20 import android.car.hardware.power.ICarPower; 21 import android.car.hardware.power.ICarPowerStateListener; 22 import android.car.userlib.CarUserManagerHelper; 23 import android.content.Context; 24 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq; 25 import android.os.Build; 26 import android.os.Handler; 27 import android.os.HandlerThread; 28 import android.os.IBinder; 29 import android.os.Looper; 30 import android.os.Message; 31 import android.os.RemoteCallbackList; 32 import android.os.RemoteException; 33 import android.os.SystemClock; 34 import android.os.SystemProperties; 35 import android.os.UserHandle; 36 import android.util.Log; 37 38 import com.android.car.hal.PowerHalService; 39 import com.android.car.hal.PowerHalService.PowerState; 40 import com.android.car.systeminterface.SystemInterface; 41 import com.android.internal.annotations.GuardedBy; 42 import com.android.internal.annotations.VisibleForTesting; 43 44 import java.io.PrintWriter; 45 import java.util.HashSet; 46 import java.util.LinkedList; 47 import java.util.Set; 48 import java.util.Timer; 49 import java.util.TimerTask; 50 51 /** 52 * Power Management service class for cars. Controls the power states and interacts with other 53 * parts of the system to ensure its own state. 54 */ 55 public class CarPowerManagementService extends ICarPower.Stub implements 56 CarServiceBase, PowerHalService.PowerEventListener { 57 private final Context mContext; 58 private final PowerHalService mHal; 59 private final SystemInterface mSystemInterface; 60 // The listeners that complete simply by returning from onStateChanged() 61 private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList(); 62 // The listeners that must indicate asynchronous completion by calling finished(). 63 private final PowerManagerCallbackList mPowerManagerListenersWithCompletion = 64 new PowerManagerCallbackList(); 65 private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>(); 66 private final Object mSimulationSleepObject = new Object(); 67 68 @GuardedBy("this") 69 private CpmsState mCurrentState; 70 @GuardedBy("this") 71 private Timer mTimer; 72 @GuardedBy("this") 73 private long mProcessingStartTime; 74 @GuardedBy("this") 75 private long mLastSleepEntryTime; 76 @GuardedBy("this") 77 private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>(); 78 @GuardedBy("this") 79 private HandlerThread mHandlerThread; 80 @GuardedBy("this") 81 private PowerHandler mHandler; 82 @GuardedBy("this") 83 private boolean mTimerActive; 84 @GuardedBy("mSimulationSleepObject") 85 private boolean mInSimulatedDeepSleepMode = false; 86 @GuardedBy("mSimulationSleepObject") 87 private boolean mWakeFromSimulatedSleep = false; 88 private int mNextWakeupSec = 0; 89 private boolean mShutdownOnFinish = false; 90 private boolean mIsBooting = true; 91 92 private final CarUserManagerHelper mCarUserManagerHelper; 93 94 // TODO: Make this OEM configurable. 95 private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000; 96 private static final int SHUTDOWN_EXTEND_MAX_MS = 5000; 97 98 // maxGarageModeRunningDurationInSecs should be equal or greater than this. 15 min for now. 99 private static final int MIN_MAX_GARAGE_MODE_DURATION_MS = 15 * 60 * 1000; 100 101 private static int sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS; 102 103 // in secs 104 private static final String PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE = 105 "android.car.garagemodeduration"; 106 107 private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> { 108 /** 109 * Old version of {@link #onCallbackDied(E, Object)} that 110 * does not provide a cookie. 111 */ 112 @Override onCallbackDied(ICarPowerStateListener listener)113 public void onCallbackDied(ICarPowerStateListener listener) { 114 Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder()); 115 CarPowerManagementService.this.doUnregisterListener(listener); 116 } 117 } 118 CarPowerManagementService( Context context, PowerHalService powerHal, SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper)119 public CarPowerManagementService( 120 Context context, PowerHalService powerHal, SystemInterface systemInterface, 121 CarUserManagerHelper carUserManagerHelper) { 122 mContext = context; 123 mHal = powerHal; 124 mSystemInterface = systemInterface; 125 mCarUserManagerHelper = carUserManagerHelper; 126 sShutdownPrepareTimeMs = mContext.getResources().getInteger( 127 R.integer.maxGarageModeRunningDurationInSecs) * 1000; 128 if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) { 129 Log.w(CarLog.TAG_POWER, 130 "maxGarageModeRunningDurationInSecs smaller than minimum required, resource:" 131 + sShutdownPrepareTimeMs + "(ms) while should exceed:" 132 + MIN_MAX_GARAGE_MODE_DURATION_MS + "(ms), Ignore resource."); 133 sShutdownPrepareTimeMs = MIN_MAX_GARAGE_MODE_DURATION_MS; 134 } 135 } 136 137 /** 138 * Create a dummy instance for unit testing purpose only. Instance constructed in this way 139 * is not safe as members expected to be non-null are null. 140 */ 141 @VisibleForTesting CarPowerManagementService()142 protected CarPowerManagementService() { 143 mContext = null; 144 mHal = null; 145 mSystemInterface = null; 146 mHandlerThread = null; 147 mHandler = new PowerHandler(Looper.getMainLooper()); 148 mCarUserManagerHelper = null; 149 } 150 151 @VisibleForTesting setShutdownPrepareTimeout(int timeoutMs)152 protected static void setShutdownPrepareTimeout(int timeoutMs) { 153 // Override the timeout to keep testing time short 154 if (timeoutMs < SHUTDOWN_EXTEND_MAX_MS) { 155 sShutdownPrepareTimeMs = SHUTDOWN_EXTEND_MAX_MS; 156 } else { 157 sShutdownPrepareTimeMs = timeoutMs; 158 } 159 } 160 161 @Override init()162 public void init() { 163 synchronized (CarPowerManagementService.this) { 164 mHandlerThread = new HandlerThread(CarLog.TAG_POWER); 165 mHandlerThread.start(); 166 mHandler = new PowerHandler(mHandlerThread.getLooper()); 167 } 168 169 mHal.setListener(this); 170 if (mHal.isPowerStateSupported()) { 171 // Initialize CPMS in WAIT_FOR_VHAL state 172 onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, CarPowerStateListener.WAIT_FOR_VHAL); 173 } else { 174 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet."); 175 onApPowerStateChange(CpmsState.ON, CarPowerStateListener.ON); 176 } 177 mSystemInterface.startDisplayStateMonitoring(this); 178 } 179 180 @Override release()181 public void release() { 182 HandlerThread handlerThread; 183 synchronized (CarPowerManagementService.this) { 184 releaseTimerLocked(); 185 mCurrentState = null; 186 mHandler.cancelAll(); 187 handlerThread = mHandlerThread; 188 } 189 handlerThread.quitSafely(); 190 try { 191 handlerThread.join(1000); 192 } catch (InterruptedException e) { 193 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join."); 194 } 195 mSystemInterface.stopDisplayStateMonitoring(); 196 mPowerManagerListeners.kill(); 197 mListenersWeAreWaitingFor.clear(); 198 mSystemInterface.releaseAllWakeLocks(); 199 } 200 201 @Override dump(PrintWriter writer)202 public void dump(PrintWriter writer) { 203 writer.println("*PowerManagementService*"); 204 writer.print("mCurrentState:" + mCurrentState); 205 writer.print(",mProcessingStartTime:" + mProcessingStartTime); 206 writer.print(",mLastSleepEntryTime:" + mLastSleepEntryTime); 207 writer.print(",mNextWakeupSec:" + mNextWakeupSec); 208 writer.print(",mShutdownOnFinish:" + mShutdownOnFinish); 209 writer.println(",sShutdownPrepareTimeMs:" + sShutdownPrepareTimeMs); 210 } 211 212 @Override onApPowerStateChange(PowerState state)213 public void onApPowerStateChange(PowerState state) { 214 PowerHandler handler; 215 synchronized (CarPowerManagementService.this) { 216 mPendingPowerStates.addFirst(new CpmsState(state)); 217 handler = mHandler; 218 } 219 handler.handlePowerStateChange(); 220 } 221 222 @VisibleForTesting clearIsBooting()223 protected void clearIsBooting() { 224 mIsBooting = false; 225 } 226 227 /** 228 * Initiate state change from CPMS directly. 229 */ onApPowerStateChange(int apState, int carPowerStateListenerState)230 private void onApPowerStateChange(int apState, int carPowerStateListenerState) { 231 CpmsState newState = new CpmsState(apState, carPowerStateListenerState); 232 PowerHandler handler; 233 synchronized (CarPowerManagementService.this) { 234 mPendingPowerStates.addFirst(newState); 235 handler = mHandler; 236 } 237 handler.handlePowerStateChange(); 238 } 239 doHandlePowerStateChange()240 private void doHandlePowerStateChange() { 241 CpmsState state; 242 PowerHandler handler; 243 synchronized (CarPowerManagementService.this) { 244 state = mPendingPowerStates.peekFirst(); 245 mPendingPowerStates.clear(); 246 if (state == null) { 247 return; 248 } 249 Log.i(CarLog.TAG_POWER, "doHandlePowerStateChange: newState=" + state.name()); 250 if (!needPowerStateChangeLocked(state)) { 251 Log.d(CarLog.TAG_POWER, "doHandlePowerStateChange no change needed"); 252 return; 253 } 254 // now real power change happens. Whatever was queued before should be all cancelled. 255 releaseTimerLocked(); 256 handler = mHandler; 257 } 258 handler.cancelProcessingComplete(); 259 Log.i(CarLog.TAG_POWER, "setCurrentState " + state.toString()); 260 CarStatsLog.logPowerState(state.mState); 261 mCurrentState = state; 262 switch (state.mState) { 263 case CpmsState.WAIT_FOR_VHAL: 264 handleWaitForVhal(state); 265 break; 266 case CpmsState.ON: 267 handleOn(); 268 break; 269 case CpmsState.SHUTDOWN_PREPARE: 270 handleShutdownPrepare(state); 271 break; 272 case CpmsState.SIMULATE_SLEEP: 273 simulateShutdownPrepare(); 274 break; 275 case CpmsState.WAIT_FOR_FINISH: 276 handleWaitForFinish(state); 277 break; 278 case CpmsState.SUSPEND: 279 // Received FINISH from VHAL 280 handleFinish(); 281 break; 282 default: 283 // Illegal state 284 // TODO: Throw exception? 285 break; 286 } 287 } 288 handleWaitForVhal(CpmsState state)289 private void handleWaitForVhal(CpmsState state) { 290 int carPowerStateListenerState = state.mCarPowerStateListenerState; 291 sendPowerManagerEvent(carPowerStateListenerState); 292 // Inspect CarPowerStateListenerState to decide which message to send via VHAL 293 switch (carPowerStateListenerState) { 294 case CarPowerStateListener.WAIT_FOR_VHAL: 295 mHal.sendWaitForVhal(); 296 break; 297 case CarPowerStateListener.SHUTDOWN_CANCELLED: 298 mHal.sendShutdownCancel(); 299 break; 300 case CarPowerStateListener.SUSPEND_EXIT: 301 mHal.sendSleepExit(); 302 break; 303 } 304 } 305 handleOn()306 private void handleOn() { 307 // Do not switch user if it is booting as there can be a race with CarServiceHelperService 308 if (mIsBooting) { 309 mIsBooting = false; 310 } else { 311 int targetUserId = mCarUserManagerHelper.getInitialUser(); 312 if (targetUserId != UserHandle.USER_SYSTEM 313 && targetUserId != mCarUserManagerHelper.getCurrentForegroundUserId()) { 314 Log.i(CarLog.TAG_POWER, "Desired user changed, switching to user:" + targetUserId); 315 mCarUserManagerHelper.switchToUserId(targetUserId); 316 } 317 } 318 mSystemInterface.setDisplayState(true); 319 sendPowerManagerEvent(CarPowerStateListener.ON); 320 mHal.sendOn(); 321 } 322 handleShutdownPrepare(CpmsState newState)323 private void handleShutdownPrepare(CpmsState newState) { 324 mSystemInterface.setDisplayState(false); 325 // Shutdown on finish if the system doesn't support deep sleep or doesn't allow it. 326 mShutdownOnFinish |= !mHal.isDeepSleepAllowed() 327 || !mSystemInterface.isSystemSupportingDeepSleep() 328 || !newState.mCanSleep; 329 if (newState.mCanPostpone) { 330 Log.i(CarLog.TAG_POWER, "starting shutdown prepare"); 331 sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE); 332 mHal.sendShutdownPrepare(); 333 doHandlePreprocessing(); 334 } else { 335 Log.i(CarLog.TAG_POWER, "starting shutdown immediately"); 336 synchronized (CarPowerManagementService.this) { 337 releaseTimerLocked(); 338 } 339 // Notify hal that we are shutting down and since it is immediate, don't schedule next 340 // wake up 341 mHal.sendShutdownStart(0); 342 // shutdown HU 343 mSystemInterface.shutdown(); 344 } 345 } 346 347 // Simulate system shutdown to Deep Sleep simulateShutdownPrepare()348 private void simulateShutdownPrepare() { 349 mSystemInterface.setDisplayState(false); 350 Log.i(CarLog.TAG_POWER, "starting shutdown prepare"); 351 sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE); 352 mHal.sendShutdownPrepare(); 353 doHandlePreprocessing(); 354 } 355 handleWaitForFinish(CpmsState state)356 private void handleWaitForFinish(CpmsState state) { 357 sendPowerManagerEvent(state.mCarPowerStateListenerState); 358 switch (state.mCarPowerStateListenerState) { 359 case CarPowerStateListener.SUSPEND_ENTER: 360 mHal.sendSleepEntry(mNextWakeupSec); 361 break; 362 case CarPowerStateListener.SHUTDOWN_ENTER: 363 mHal.sendShutdownStart(mNextWakeupSec); 364 break; 365 } 366 } 367 handleFinish()368 private void handleFinish() { 369 boolean mustShutDown; 370 boolean simulatedMode; 371 synchronized (mSimulationSleepObject) { 372 simulatedMode = mInSimulatedDeepSleepMode; 373 mustShutDown = mShutdownOnFinish && !simulatedMode; 374 } 375 if (mustShutDown) { 376 // shutdown HU 377 mSystemInterface.shutdown(); 378 } else { 379 doHandleDeepSleep(simulatedMode); 380 } 381 } 382 383 @GuardedBy("this") releaseTimerLocked()384 private void releaseTimerLocked() { 385 synchronized (CarPowerManagementService.this) { 386 if (mTimer != null) { 387 mTimer.cancel(); 388 } 389 mTimer = null; 390 mTimerActive = false; 391 } 392 } 393 doHandlePreprocessing()394 private void doHandlePreprocessing() { 395 int pollingCount = (sShutdownPrepareTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1; 396 if (Build.IS_USERDEBUG || Build.IS_ENG) { 397 int shutdownPrepareTimeOverrideInSecs = 398 SystemProperties.getInt(PROP_MAX_GARAGE_MODE_DURATION_OVERRIDE, -1); 399 if (shutdownPrepareTimeOverrideInSecs >= 0) { 400 pollingCount = 401 (shutdownPrepareTimeOverrideInSecs * 1000 / SHUTDOWN_POLLING_INTERVAL_MS) 402 + 1; 403 Log.i(CarLog.TAG_POWER, 404 "Garage mode duration overridden secs:" 405 + shutdownPrepareTimeOverrideInSecs); 406 } 407 } 408 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: " 409 + sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount); 410 synchronized (CarPowerManagementService.this) { 411 mProcessingStartTime = SystemClock.elapsedRealtime(); 412 releaseTimerLocked(); 413 mTimer = new Timer(); 414 mTimerActive = true; 415 mTimer.scheduleAtFixedRate( 416 new ShutdownProcessingTimerTask(pollingCount), 417 0 /*delay*/, 418 SHUTDOWN_POLLING_INTERVAL_MS); 419 } 420 } 421 sendPowerManagerEvent(int newState)422 private void sendPowerManagerEvent(int newState) { 423 // Broadcast to the listeners that do not signal completion 424 notifyListeners(mPowerManagerListeners, newState); 425 426 // SHUTDOWN_PREPARE is the only state where we need 427 // to maintain callbacks from listener components. 428 boolean allowCompletion = (newState == CarPowerStateListener.SHUTDOWN_PREPARE); 429 430 // Fully populate mListenersWeAreWaitingFor before calling any onStateChanged() 431 // for the listeners that signal completion. 432 // Otherwise, if the first listener calls finish() synchronously, we will 433 // see the list go empty and we will think that we are done. 434 boolean haveSomeCompleters = false; 435 PowerManagerCallbackList completingListeners = new PowerManagerCallbackList(); 436 synchronized (mListenersWeAreWaitingFor) { 437 mListenersWeAreWaitingFor.clear(); 438 int idx = mPowerManagerListenersWithCompletion.beginBroadcast(); 439 while (idx-- > 0) { 440 ICarPowerStateListener listener = 441 mPowerManagerListenersWithCompletion.getBroadcastItem(idx); 442 completingListeners.register(listener); 443 if (allowCompletion) { 444 mListenersWeAreWaitingFor.add(listener.asBinder()); 445 haveSomeCompleters = true; 446 } 447 } 448 mPowerManagerListenersWithCompletion.finishBroadcast(); 449 } 450 // Broadcast to the listeners that DO signal completion 451 notifyListeners(completingListeners, newState); 452 453 if (allowCompletion && !haveSomeCompleters) { 454 // No jobs need to signal completion. So we are now complete. 455 signalComplete(); 456 } 457 } 458 notifyListeners(PowerManagerCallbackList listenerList, int newState)459 private void notifyListeners(PowerManagerCallbackList listenerList, int newState) { 460 int idx = listenerList.beginBroadcast(); 461 while (idx-- > 0) { 462 ICarPowerStateListener listener = listenerList.getBroadcastItem(idx); 463 try { 464 listener.onStateChanged(newState); 465 } catch (RemoteException e) { 466 // It's likely the connection snapped. Let binder death handle the situation. 467 Log.e(CarLog.TAG_POWER, "onStateChanged() call failed: " + e, e); 468 } 469 } 470 listenerList.finishBroadcast(); 471 } 472 doHandleDeepSleep(boolean simulatedMode)473 private void doHandleDeepSleep(boolean simulatedMode) { 474 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call 475 // enterDeepSleep should force sleep entry even if wake lock is kept. 476 mSystemInterface.switchToPartialWakeLock(); 477 PowerHandler handler; 478 synchronized (CarPowerManagementService.this) { 479 handler = mHandler; 480 } 481 handler.cancelProcessingComplete(); 482 synchronized (CarPowerManagementService.this) { 483 mLastSleepEntryTime = SystemClock.elapsedRealtime(); 484 } 485 int nextListenerState; 486 if (simulatedMode) { 487 simulateSleepByLooping(); 488 nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED; 489 } else { 490 boolean sleepSucceeded = mSystemInterface.enterDeepSleep(); 491 if (!sleepSucceeded) { 492 // VHAL should transition CPMS to shutdown. 493 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down."); 494 mSystemInterface.shutdown(); 495 } 496 nextListenerState = CarPowerStateListener.SUSPEND_EXIT; 497 } 498 // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever. 499 mNextWakeupSec = 0; 500 mSystemInterface.refreshDisplayBrightness(); 501 onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState); 502 } 503 needPowerStateChangeLocked(CpmsState newState)504 private boolean needPowerStateChangeLocked(CpmsState newState) { 505 if (newState == null) { 506 return false; 507 } else if (mCurrentState == null) { 508 return true; 509 } else if (mCurrentState.equals(newState)) { 510 return false; 511 } 512 513 // The following switch/case enforces the allowed state transitions. 514 switch (mCurrentState.mState) { 515 case CpmsState.WAIT_FOR_VHAL: 516 return (newState.mState == CpmsState.ON) 517 || (newState.mState == CpmsState.SHUTDOWN_PREPARE); 518 case CpmsState.SUSPEND: 519 return newState.mState == CpmsState.WAIT_FOR_VHAL; 520 case CpmsState.ON: 521 return (newState.mState == CpmsState.SHUTDOWN_PREPARE) 522 || (newState.mState == CpmsState.SIMULATE_SLEEP); 523 case CpmsState.SHUTDOWN_PREPARE: 524 // If VHAL sends SHUTDOWN_IMMEDIATELY while in SHUTDOWN_PREPARE state, do it. 525 return ((newState.mState == CpmsState.SHUTDOWN_PREPARE) && !newState.mCanPostpone) 526 || (newState.mState == CpmsState.WAIT_FOR_FINISH) 527 || (newState.mState == CpmsState.WAIT_FOR_VHAL); 528 case CpmsState.SIMULATE_SLEEP: 529 return true; 530 case CpmsState.WAIT_FOR_FINISH: 531 return newState.mState == CpmsState.SUSPEND; 532 default: 533 Log.e(CarLog.TAG_POWER, "Unhandled state transition: currentState=" 534 + mCurrentState.name() + ", newState=" + newState.name()); 535 return false; 536 } 537 } 538 doHandleProcessingComplete()539 private void doHandleProcessingComplete() { 540 synchronized (CarPowerManagementService.this) { 541 releaseTimerLocked(); 542 if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) { 543 // entered sleep after processing start. So this could be duplicate request. 544 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore"); 545 return; 546 } 547 } 548 549 if (mShutdownOnFinish) { 550 onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SHUTDOWN_ENTER); 551 } else { 552 onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SUSPEND_ENTER); 553 } 554 } 555 556 @Override onDisplayBrightnessChange(int brightness)557 public void onDisplayBrightnessChange(int brightness) { 558 PowerHandler handler; 559 synchronized (CarPowerManagementService.this) { 560 handler = mHandler; 561 } 562 handler.handleDisplayBrightnessChange(brightness); 563 } 564 doHandleDisplayBrightnessChange(int brightness)565 private void doHandleDisplayBrightnessChange(int brightness) { 566 mSystemInterface.setDisplayBrightness(brightness); 567 } 568 doHandleMainDisplayStateChange(boolean on)569 private void doHandleMainDisplayStateChange(boolean on) { 570 Log.w(CarLog.TAG_POWER, "Unimplemented: doHandleMainDisplayStateChange() - on = " + on); 571 } 572 handleMainDisplayChanged(boolean on)573 public void handleMainDisplayChanged(boolean on) { 574 PowerHandler handler; 575 synchronized (CarPowerManagementService.this) { 576 handler = mHandler; 577 } 578 handler.handleMainDisplayStateChange(on); 579 } 580 581 /** 582 * Send display brightness to VHAL. 583 * @param brightness value 0-100% 584 */ sendDisplayBrightness(int brightness)585 public void sendDisplayBrightness(int brightness) { 586 mHal.sendDisplayBrightness(brightness); 587 } 588 getHandler()589 public synchronized Handler getHandler() { 590 return mHandler; 591 } 592 593 // Binder interface for general use. 594 // The listener is not required (or allowed) to call finished(). 595 @Override registerListener(ICarPowerStateListener listener)596 public void registerListener(ICarPowerStateListener listener) { 597 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 598 mPowerManagerListeners.register(listener); 599 } 600 601 // Binder interface for Car services only. 602 // After the listener completes its processing, it must call finished(). 603 @Override registerListenerWithCompletion(ICarPowerStateListener listener)604 public void registerListenerWithCompletion(ICarPowerStateListener listener) { 605 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 606 ICarImpl.assertCallingFromSystemProcessOrSelf(); 607 608 mPowerManagerListenersWithCompletion.register(listener); 609 // TODO: Need to send current state to newly registered listener? If so, need to handle 610 // completion for SHUTDOWN_PREPARE state 611 } 612 613 @Override unregisterListener(ICarPowerStateListener listener)614 public void unregisterListener(ICarPowerStateListener listener) { 615 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 616 doUnregisterListener(listener); 617 } 618 doUnregisterListener(ICarPowerStateListener listener)619 private void doUnregisterListener(ICarPowerStateListener listener) { 620 mPowerManagerListeners.unregister(listener); 621 boolean found = mPowerManagerListenersWithCompletion.unregister(listener); 622 if (found) { 623 // Remove this from the completion list (if it's there) 624 finishedImpl(listener.asBinder()); 625 } 626 } 627 628 @Override requestShutdownOnNextSuspend()629 public void requestShutdownOnNextSuspend() { 630 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 631 mShutdownOnFinish = true; 632 } 633 634 @Override finished(ICarPowerStateListener listener)635 public void finished(ICarPowerStateListener listener) { 636 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 637 ICarImpl.assertCallingFromSystemProcessOrSelf(); 638 finishedImpl(listener.asBinder()); 639 } 640 641 @Override scheduleNextWakeupTime(int seconds)642 public synchronized void scheduleNextWakeupTime(int seconds) { 643 if (seconds < 0) { 644 Log.w(CarLog.TAG_POWER, "Next wake up can not be in negative time. Ignoring!"); 645 return; 646 } 647 if (!mHal.isTimedWakeupAllowed()) { 648 Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping"); 649 mNextWakeupSec = 0; 650 return; 651 } 652 if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) { 653 mNextWakeupSec = seconds; 654 } else { 655 Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter " 656 + "scheduled time"); 657 } 658 } 659 finishedImpl(IBinder binder)660 private void finishedImpl(IBinder binder) { 661 boolean allAreComplete = false; 662 synchronized (mListenersWeAreWaitingFor) { 663 boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder); 664 allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty(); 665 } 666 if (allAreComplete) { 667 signalComplete(); 668 } 669 } 670 signalComplete()671 private void signalComplete() { 672 if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE 673 || mCurrentState.mState == CpmsState.SIMULATE_SLEEP) { 674 PowerHandler powerHandler; 675 // All apps are ready to shutdown/suspend. 676 synchronized (CarPowerManagementService.this) { 677 if (!mShutdownOnFinish) { 678 if (mLastSleepEntryTime > mProcessingStartTime 679 && mLastSleepEntryTime < SystemClock.elapsedRealtime()) { 680 Log.i(CarLog.TAG_POWER, "signalComplete: Already slept!"); 681 return; 682 } 683 } 684 powerHandler = mHandler; 685 } 686 Log.i(CarLog.TAG_POWER, "Apps are finished, call handleProcessingComplete()"); 687 powerHandler.handleProcessingComplete(); 688 } 689 } 690 691 private class PowerHandler extends Handler { 692 private final int MSG_POWER_STATE_CHANGE = 0; 693 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1; 694 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2; 695 private final int MSG_PROCESSING_COMPLETE = 3; 696 697 // Do not handle this immediately but with some delay as there can be a race between 698 // display off due to rear view camera and delivery to here. 699 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500; 700 PowerHandler(Looper looper)701 private PowerHandler(Looper looper) { 702 super(looper); 703 } 704 handlePowerStateChange()705 private void handlePowerStateChange() { 706 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE); 707 sendMessage(msg); 708 } 709 handleDisplayBrightnessChange(int brightness)710 private void handleDisplayBrightnessChange(int brightness) { 711 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0); 712 sendMessage(msg); 713 } 714 handleMainDisplayStateChange(boolean on)715 private void handleMainDisplayStateChange(boolean on) { 716 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 717 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on)); 718 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS); 719 } 720 handleProcessingComplete()721 private void handleProcessingComplete() { 722 removeMessages(MSG_PROCESSING_COMPLETE); 723 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE); 724 sendMessage(msg); 725 } 726 cancelProcessingComplete()727 private void cancelProcessingComplete() { 728 removeMessages(MSG_PROCESSING_COMPLETE); 729 } 730 cancelAll()731 private void cancelAll() { 732 removeMessages(MSG_POWER_STATE_CHANGE); 733 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE); 734 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 735 removeMessages(MSG_PROCESSING_COMPLETE); 736 } 737 738 @Override handleMessage(Message msg)739 public void handleMessage(Message msg) { 740 switch (msg.what) { 741 case MSG_POWER_STATE_CHANGE: 742 doHandlePowerStateChange(); 743 break; 744 case MSG_DISPLAY_BRIGHTNESS_CHANGE: 745 doHandleDisplayBrightnessChange(msg.arg1); 746 break; 747 case MSG_MAIN_DISPLAY_STATE_CHANGE: 748 doHandleMainDisplayStateChange((Boolean) msg.obj); 749 break; 750 case MSG_PROCESSING_COMPLETE: 751 doHandleProcessingComplete(); 752 break; 753 } 754 } 755 } 756 757 private class ShutdownProcessingTimerTask extends TimerTask { 758 private final int mExpirationCount; 759 private int mCurrentCount; 760 ShutdownProcessingTimerTask(int expirationCount)761 private ShutdownProcessingTimerTask(int expirationCount) { 762 mExpirationCount = expirationCount; 763 mCurrentCount = 0; 764 } 765 766 @Override run()767 public void run() { 768 synchronized (CarPowerManagementService.this) { 769 if (!mTimerActive) { 770 // Ignore timer expiration since we got cancelled 771 return; 772 } 773 mCurrentCount++; 774 if (mCurrentCount > mExpirationCount) { 775 PowerHandler handler; 776 releaseTimerLocked(); 777 handler = mHandler; 778 handler.handleProcessingComplete(); 779 } else { 780 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS); 781 } 782 } 783 } 784 } 785 786 private static class CpmsState { 787 // NOTE: When modifying states below, make sure to update CarPowerStateChanged.State in 788 // frameworks/base/cmds/statsd/src/atoms.proto also. 789 public static final int WAIT_FOR_VHAL = 0; 790 public static final int ON = 1; 791 public static final int SHUTDOWN_PREPARE = 2; 792 public static final int WAIT_FOR_FINISH = 3; 793 public static final int SUSPEND = 4; 794 public static final int SIMULATE_SLEEP = 5; 795 796 /* Config values from AP_POWER_STATE_REQ */ 797 public final boolean mCanPostpone; 798 public final boolean mCanSleep; 799 /* Message sent to CarPowerStateListener in response to this state */ 800 public final int mCarPowerStateListenerState; 801 /* One of the above state variables */ 802 public final int mState; 803 804 /** 805 * This constructor takes a PowerHalService.PowerState object and creates the corresponding 806 * CPMS state from it. 807 */ CpmsState(PowerState halPowerState)808 CpmsState(PowerState halPowerState) { 809 switch (halPowerState.mState) { 810 case VehicleApPowerStateReq.ON: 811 this.mCanPostpone = false; 812 this.mCanSleep = false; 813 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(ON); 814 this.mState = ON; 815 break; 816 case VehicleApPowerStateReq.SHUTDOWN_PREPARE: 817 this.mCanPostpone = halPowerState.canPostponeShutdown(); 818 this.mCanSleep = halPowerState.canEnterDeepSleep(); 819 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState( 820 SHUTDOWN_PREPARE); 821 this.mState = SHUTDOWN_PREPARE; 822 break; 823 case VehicleApPowerStateReq.CANCEL_SHUTDOWN: 824 this.mCanPostpone = false; 825 this.mCanSleep = false; 826 this.mCarPowerStateListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED; 827 this.mState = WAIT_FOR_VHAL; 828 break; 829 case VehicleApPowerStateReq.FINISHED: 830 this.mCanPostpone = false; 831 this.mCanSleep = false; 832 this.mCarPowerStateListenerState = cpmsStateToPowerStateListenerState(SUSPEND); 833 this.mState = SUSPEND; 834 break; 835 default: 836 // Illegal state from PowerState. Throw an exception? 837 this.mCanPostpone = false; 838 this.mCanSleep = false; 839 this.mCarPowerStateListenerState = 0; 840 this.mState = 0; 841 break; 842 } 843 } 844 CpmsState(int state)845 CpmsState(int state) { 846 this(state, cpmsStateToPowerStateListenerState(state)); 847 } 848 CpmsState(int state, int carPowerStateListenerState)849 CpmsState(int state, int carPowerStateListenerState) { 850 this.mCanPostpone = (state == SIMULATE_SLEEP); 851 this.mCanSleep = (state == SIMULATE_SLEEP); 852 this.mCarPowerStateListenerState = carPowerStateListenerState; 853 this.mState = state; 854 } 855 name()856 public String name() { 857 String baseName; 858 switch(mState) { 859 case WAIT_FOR_VHAL: baseName = "WAIT_FOR_VHAL"; break; 860 case ON: baseName = "ON"; break; 861 case SHUTDOWN_PREPARE: baseName = "SHUTDOWN_PREPARE"; break; 862 case WAIT_FOR_FINISH: baseName = "WAIT_FOR_FINISH"; break; 863 case SUSPEND: baseName = "SUSPEND"; break; 864 case SIMULATE_SLEEP: baseName = "SIMULATE_SLEEP"; break; 865 default: baseName = "<unknown>"; break; 866 } 867 return baseName + "(" + mState + ")"; 868 } 869 cpmsStateToPowerStateListenerState(int state)870 private static int cpmsStateToPowerStateListenerState(int state) { 871 int powerStateListenerState = 0; 872 873 // Set the CarPowerStateListenerState based on current state 874 switch (state) { 875 case ON: 876 powerStateListenerState = CarPowerStateListener.ON; 877 break; 878 case SHUTDOWN_PREPARE: 879 powerStateListenerState = CarPowerStateListener.SHUTDOWN_PREPARE; 880 break; 881 case SUSPEND: 882 powerStateListenerState = CarPowerStateListener.SUSPEND_ENTER; 883 break; 884 case WAIT_FOR_VHAL: 885 case WAIT_FOR_FINISH: 886 default: 887 // Illegal state for this constructor. Throw an exception? 888 break; 889 } 890 return powerStateListenerState; 891 } 892 893 @Override equals(Object o)894 public boolean equals(Object o) { 895 if (this == o) { 896 return true; 897 } 898 if (!(o instanceof CpmsState)) { 899 return false; 900 } 901 CpmsState that = (CpmsState) o; 902 return this.mState == that.mState 903 && this.mCanSleep == that.mCanSleep 904 && this.mCanPostpone == that.mCanPostpone 905 && this.mCarPowerStateListenerState == that.mCarPowerStateListenerState; 906 } 907 908 @Override toString()909 public String toString() { 910 return "CpmsState canSleep:" + mCanSleep + ", canPostpone=" + mCanPostpone 911 + ", carPowerStateListenerState=" + mCarPowerStateListenerState 912 + ", CpmsState=" + this.name(); 913 } 914 } 915 916 /** 917 * Resume after a manually-invoked suspend. 918 * Invoked using "adb shell dumpsys activity service com.android.car resume". 919 */ forceSimulatedResume()920 public void forceSimulatedResume() { 921 PowerHandler handler; 922 synchronized (this) { 923 // Cancel Garage Mode in case it's running 924 mPendingPowerStates.addFirst(new CpmsState(CpmsState.WAIT_FOR_VHAL, 925 CarPowerStateListener.SHUTDOWN_CANCELLED)); 926 handler = mHandler; 927 } 928 handler.handlePowerStateChange(); 929 930 synchronized (mSimulationSleepObject) { 931 mWakeFromSimulatedSleep = true; 932 mSimulationSleepObject.notify(); 933 } 934 } 935 936 /** 937 * Manually enter simulated suspend (Deep Sleep) mode 938 * Invoked using "adb shell dumpsys activity service com.android.car suspend". 939 * This is similar to 'onApPowerStateChange()' except that it needs to create a CpmsState 940 * that is not directly derived from a VehicleApPowerStateReq. 941 */ forceSimulatedSuspend()942 public void forceSimulatedSuspend() { 943 synchronized (mSimulationSleepObject) { 944 mInSimulatedDeepSleepMode = true; 945 mWakeFromSimulatedSleep = false; 946 } 947 PowerHandler handler; 948 synchronized (this) { 949 mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP, 950 CarPowerStateListener.SHUTDOWN_PREPARE)); 951 handler = mHandler; 952 } 953 handler.handlePowerStateChange(); 954 } 955 956 // In a real Deep Sleep, the hardware removes power from the CPU (but retains power 957 // on the RAM). This puts the processor to sleep. Upon some external signal, power 958 // is re-applied to the CPU, and processing resumes right where it left off. 959 // We simulate this behavior by simply going into a loop. 960 // We exit the loop when forceResume() is called. simulateSleepByLooping()961 private void simulateSleepByLooping() { 962 Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by looping"); 963 synchronized (mSimulationSleepObject) { 964 while (!mWakeFromSimulatedSleep) { 965 try { 966 mSimulationSleepObject.wait(); 967 } catch (InterruptedException ignored) { 968 } 969 } 970 mInSimulatedDeepSleepMode = false; 971 } 972 Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation loop"); 973 } 974 } 975