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.content.Context; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.IBinder; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.RemoteCallbackList; 29 import android.os.RemoteException; 30 import android.os.SystemClock; 31 import android.util.Log; 32 33 import com.android.car.hal.PowerHalService; 34 import com.android.car.hal.PowerHalService.PowerState; 35 import com.android.car.systeminterface.SystemInterface; 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.annotations.VisibleForTesting; 38 39 import java.io.PrintWriter; 40 import java.util.LinkedList; 41 import java.util.Map; 42 import java.util.Timer; 43 import java.util.TimerTask; 44 import java.util.concurrent.ConcurrentHashMap; 45 import java.util.concurrent.CopyOnWriteArrayList; 46 47 public class CarPowerManagementService extends ICarPower.Stub implements CarServiceBase, 48 PowerHalService.PowerEventListener { 49 50 /** 51 * Listener for other services to monitor power events. 52 */ 53 public interface PowerServiceEventListener { 54 /** 55 * Shutdown is happening 56 */ 57 void onShutdown(); 58 59 /** 60 * Entering deep sleep. 61 */ 62 void onSleepEntry(); 63 64 /** 65 * Got out of deep sleep. 66 */ 67 void onSleepExit(); 68 } 69 70 /** 71 * Interface for components requiring processing time before shutting-down or 72 * entering sleep, and wake-up after shut-down. 73 */ 74 public interface PowerEventProcessingHandler { 75 /** 76 * Called before shutdown or sleep entry to allow running some processing. This call 77 * should only queue such task in different thread and should return quickly. 78 * Blocking inside this call can trigger watchdog timer which can terminate the 79 * whole system. 80 * @param shuttingDown whether system is shutting down or not (= sleep entry). 81 * @return time necessary to run processing in ms. should return 0 if there is no 82 * processing necessary. 83 */ 84 long onPrepareShutdown(boolean shuttingDown); 85 86 /** 87 * Called when power state is changed to ON state. Display can be either on or off. 88 * @param displayOn 89 */ 90 void onPowerOn(boolean displayOn); 91 92 /** 93 * Returns wake up time after system is fully shutdown. Power controller will power on 94 * the system after this time. This power on is meant for regular maintenance kind of 95 * operation. 96 * @return 0 of wake up is not necessary. 97 */ 98 int getWakeupTime(); 99 } 100 101 private final Context mContext; 102 private final PowerHalService mHal; 103 private final SystemInterface mSystemInterface; 104 105 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners = 106 new CopyOnWriteArrayList<>(); 107 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper> 108 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>(); 109 private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList(); 110 private final Map<IBinder, Integer> mPowerManagerListenerTokens = new ConcurrentHashMap<>(); 111 private int mTokenValue = 1; 112 113 @GuardedBy("this") 114 private PowerState mCurrentState; 115 @GuardedBy("this") 116 private Timer mTimer; 117 @GuardedBy("this") 118 private long mProcessingStartTime; 119 @GuardedBy("this") 120 private long mLastSleepEntryTime; 121 @GuardedBy("this") 122 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>(); 123 @GuardedBy("this") 124 private HandlerThread mHandlerThread; 125 @GuardedBy("this") 126 private PowerHandler mHandler; 127 private int mBootReason; 128 private boolean mShutdownOnNextSuspend = false; 129 130 // TODO: Make this OEM configurable. 131 private final static int APP_EXTEND_MAX_MS = 10000; 132 private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000; 133 private final static int SHUTDOWN_EXTEND_MAX_MS = 5000; 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 141 public void onCallbackDied(ICarPowerStateListener listener) { 142 Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder()); 143 CarPowerManagementService.this.doUnregisterListener(listener); 144 } 145 } 146 147 public CarPowerManagementService(Context context, PowerHalService powerHal, 148 SystemInterface systemInterface) { 149 mContext = context; 150 mHal = powerHal; 151 mSystemInterface = systemInterface; 152 } 153 154 /** 155 * Create a dummy instance for unit testing purpose only. Instance constructed in this way 156 * is not safe as members expected to be non-null are null. 157 */ 158 @VisibleForTesting 159 protected CarPowerManagementService() { 160 mContext = null; 161 mHal = null; 162 mSystemInterface = null; 163 mHandlerThread = null; 164 mHandler = new PowerHandler(Looper.getMainLooper()); 165 } 166 167 @Override 168 public void init() { 169 synchronized (this) { 170 mHandlerThread = new HandlerThread(CarLog.TAG_POWER); 171 mHandlerThread.start(); 172 mHandler = new PowerHandler(mHandlerThread.getLooper()); 173 } 174 175 mHal.setListener(this); 176 if (mHal.isPowerStateSupported()) { 177 mHal.sendBootComplete(); 178 PowerState currentState = mHal.getCurrentPowerState(); 179 if (currentState != null) { 180 onApPowerStateChange(currentState); 181 } else { 182 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during " 183 + "initialization"); 184 } 185 } else { 186 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet."); 187 onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0)); 188 mSystemInterface.switchToFullWakeLock(); 189 } 190 mSystemInterface.startDisplayStateMonitoring(this); 191 } 192 193 @Override 194 public void release() { 195 HandlerThread handlerThread; 196 synchronized (this) { 197 releaseTimerLocked(); 198 mCurrentState = null; 199 mHandler.cancelAll(); 200 handlerThread = mHandlerThread; 201 } 202 handlerThread.quitSafely(); 203 try { 204 handlerThread.join(1000); 205 } catch (InterruptedException e) { 206 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join."); 207 } 208 mSystemInterface.stopDisplayStateMonitoring(); 209 mListeners.clear(); 210 mPowerEventProcessingHandlers.clear(); 211 mPowerManagerListeners.kill(); 212 mPowerManagerListenerTokens.clear(); 213 mSystemInterface.releaseAllWakeLocks(); 214 } 215 216 /** 217 * Register listener to monitor power event. There is no unregister counter-part and the list 218 * will be cleared when the service is released. 219 * @param listener 220 */ 221 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) { 222 mListeners.add(listener); 223 } 224 225 /** 226 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or 227 * sleep entry. There is no unregister counter-part and the list 228 * will be cleared when the service is released. 229 * @param handler 230 */ 231 public synchronized void registerPowerEventProcessingHandler( 232 PowerEventProcessingHandler handler) { 233 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler)); 234 // onPowerOn will not be called if power on notification is already done inside the 235 // handler thread. So request it once again here. Wrapper will have its own 236 // gatekeeping to prevent calling onPowerOn twice. 237 mHandler.handlePowerOn(); 238 } 239 240 /** 241 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes 242 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than 243 * that, and this call can be called in such case to trigger shutdown without waiting further. 244 * 245 * @param handler PowerEventProcessingHandler that was already registered with 246 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not 247 * registered before, this call will be ignored. 248 */ 249 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) { 250 long processingTime = 0; 251 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 252 if (wrapper.handler == handler) { 253 wrapper.markProcessingDone(); 254 } else if (!wrapper.isProcessingDone()) { 255 processingTime = Math.max(processingTime, wrapper.getProcessingTime()); 256 } 257 } 258 synchronized (mPowerManagerListenerTokens) { 259 if (!mPowerManagerListenerTokens.isEmpty()) { 260 processingTime += APP_EXTEND_MAX_MS; 261 } 262 } 263 long now = SystemClock.elapsedRealtime(); 264 long startTime; 265 boolean shouldShutdown = true; 266 PowerHandler powerHandler; 267 synchronized (this) { 268 startTime = mProcessingStartTime; 269 if (mCurrentState == null) { 270 return; 271 } 272 if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) { 273 return; 274 } 275 if (mCurrentState.canEnterDeepSleep() && !mShutdownOnNextSuspend) { 276 shouldShutdown = false; 277 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) { 278 // already slept 279 return; 280 } 281 } 282 powerHandler = mHandler; 283 } 284 if ((startTime + processingTime) <= now) { 285 Log.i(CarLog.TAG_POWER, "Processing all done"); 286 powerHandler.handleProcessingComplete(shouldShutdown); 287 } 288 } 289 290 @Override 291 public void dump(PrintWriter writer) { 292 writer.println("*PowerManagementService*"); 293 writer.print("mCurrentState:" + mCurrentState); 294 writer.print(",mProcessingStartTime:" + mProcessingStartTime); 295 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime); 296 writer.println("**PowerEventProcessingHandlers"); 297 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 298 writer.println(wrapper.toString()); 299 } 300 } 301 302 @Override 303 public void onBootReasonReceived(int bootReason) { 304 mBootReason = bootReason; 305 } 306 307 @Override 308 public void onApPowerStateChange(PowerState state) { 309 PowerHandler handler; 310 synchronized (this) { 311 mPendingPowerStates.addFirst(state); 312 handler = mHandler; 313 } 314 handler.handlePowerStateChange(); 315 } 316 317 private void doHandlePowerStateChange() { 318 PowerState state = null; 319 PowerHandler handler; 320 synchronized (this) { 321 state = mPendingPowerStates.peekFirst(); 322 mPendingPowerStates.clear(); 323 if (state == null) { 324 return; 325 } 326 if (!needPowerStateChange(state)) { 327 return; 328 } 329 // now real power change happens. Whatever was queued before should be all cancelled. 330 releaseTimerLocked(); 331 handler = mHandler; 332 } 333 handler.cancelProcessingComplete(); 334 335 Log.i(CarLog.TAG_POWER, "Power state change:" + state); 336 switch (state.mState) { 337 case PowerHalService.STATE_ON_DISP_OFF: 338 handleDisplayOff(state); 339 notifyPowerOn(false); 340 break; 341 case PowerHalService.STATE_ON_FULL: 342 handleFullOn(state); 343 notifyPowerOn(true); 344 break; 345 case PowerHalService.STATE_SHUTDOWN_PREPARE: 346 handleShutdownPrepare(state); 347 break; 348 } 349 } 350 351 private void handleDisplayOff(PowerState newState) { 352 setCurrentState(newState); 353 mSystemInterface.setDisplayState(false); 354 } 355 356 private void handleFullOn(PowerState newState) { 357 setCurrentState(newState); 358 mSystemInterface.setDisplayState(true); 359 } 360 361 @VisibleForTesting 362 protected void notifyPowerOn(boolean displayOn) { 363 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 364 wrapper.callOnPowerOn(displayOn); 365 } 366 } 367 368 @VisibleForTesting 369 protected long notifyPrepareShutdown(boolean shuttingDown) { 370 long processingTimeMs = 0; 371 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 372 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown); 373 if (handlerProcessingTime > processingTimeMs) { 374 processingTimeMs = handlerProcessingTime; 375 } 376 } 377 // Add time for powerManager events 378 processingTimeMs += sendPowerManagerEvent(shuttingDown); 379 return processingTimeMs; 380 } 381 382 private void handleShutdownPrepare(PowerState newState) { 383 setCurrentState(newState); 384 mSystemInterface.setDisplayState(false);; 385 boolean shouldShutdown = true; 386 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() && 387 newState.canEnterDeepSleep() && !mShutdownOnNextSuspend) { 388 Log.i(CarLog.TAG_POWER, "starting sleep"); 389 shouldShutdown = false; 390 doHandlePreprocessing(shouldShutdown); 391 return; 392 } else if (newState.canPostponeShutdown()) { 393 Log.i(CarLog.TAG_POWER, "starting shutdown with processing"); 394 doHandlePreprocessing(shouldShutdown); 395 } else { 396 Log.i(CarLog.TAG_POWER, "starting shutdown immediately"); 397 synchronized (this) { 398 releaseTimerLocked(); 399 } 400 doHandleShutdown(); 401 } 402 } 403 404 @GuardedBy("this") 405 private void releaseTimerLocked() { 406 if (mTimer != null) { 407 mTimer.cancel(); 408 } 409 mTimer = null; 410 } 411 412 private void doHandlePreprocessing(boolean shuttingDown) { 413 long processingTimeMs = 0; 414 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 415 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown); 416 if (handlerProcessingTime > 0) { 417 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime); 418 } 419 if (handlerProcessingTime > processingTimeMs) { 420 processingTimeMs = handlerProcessingTime; 421 } 422 } 423 // Add time for powerManager events 424 processingTimeMs += sendPowerManagerEvent(shuttingDown); 425 if (processingTimeMs > 0) { 426 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1; 427 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs + 428 " ms, adding polling:" + pollingCount); 429 synchronized (this) { 430 mProcessingStartTime = SystemClock.elapsedRealtime(); 431 releaseTimerLocked(); 432 mTimer = new Timer(); 433 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown, 434 pollingCount), 435 0 /*delay*/, 436 SHUTDOWN_POLLING_INTERVAL_MS); 437 } 438 } else { 439 PowerHandler handler; 440 synchronized (this) { 441 handler = mHandler; 442 } 443 handler.handleProcessingComplete(shuttingDown); 444 } 445 } 446 447 private long sendPowerManagerEvent(boolean shuttingDown) { 448 long processingTimeMs = 0; 449 int newState = shuttingDown ? CarPowerStateListener.SHUTDOWN_ENTER : 450 CarPowerStateListener.SUSPEND_ENTER; 451 synchronized (mPowerManagerListenerTokens) { 452 mPowerManagerListenerTokens.clear(); 453 int i = mPowerManagerListeners.beginBroadcast(); 454 while (i-- > 0) { 455 try { 456 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i); 457 listener.onStateChanged(newState, mTokenValue); 458 mPowerManagerListenerTokens.put(listener.asBinder(), mTokenValue); 459 mTokenValue++; 460 } catch (RemoteException e) { 461 // Its likely the connection snapped. Let binder death handle the situation. 462 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e); 463 } 464 } 465 mPowerManagerListeners.finishBroadcast(); 466 if (!mPowerManagerListenerTokens.isEmpty()) { 467 Log.i(CarLog.TAG_POWER, "mPowerMangerListenerTokens not empty, add APP_EXTEND_MAX_MS"); 468 processingTimeMs += APP_EXTEND_MAX_MS; 469 } 470 } 471 return processingTimeMs; 472 } 473 474 private void doHandleDeepSleep() { 475 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call 476 // enterDeepSleep should force sleep entry even if wake lock is kept. 477 mSystemInterface.switchToPartialWakeLock(); 478 PowerHandler handler; 479 synchronized (this) { 480 handler = mHandler; 481 } 482 handler.cancelProcessingComplete(); 483 for (PowerServiceEventListener listener : mListeners) { 484 listener.onSleepEntry(); 485 } 486 int wakeupTimeSec = getWakeupTime(); 487 mHal.sendSleepEntry(); 488 synchronized (this) { 489 mLastSleepEntryTime = SystemClock.elapsedRealtime(); 490 } 491 if (mSystemInterface.enterDeepSleep(wakeupTimeSec) == false) { 492 // System did not suspend. Need to shutdown 493 // TODO: Shutdown gracefully 494 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Need to shutdown"); 495 } 496 mHal.sendSleepExit(); 497 for (PowerServiceEventListener listener : mListeners) { 498 listener.onSleepExit(); 499 } 500 // Notify applications 501 int i = mPowerManagerListeners.beginBroadcast(); 502 while (i-- > 0) { 503 try { 504 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i); 505 listener.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, 0); 506 } catch (RemoteException e) { 507 // Its likely the connection snapped. Let binder death handle the situation. 508 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e); 509 } 510 } 511 mPowerManagerListeners.finishBroadcast(); 512 513 if (mSystemInterface.isWakeupCausedByTimer()) { 514 doHandlePreprocessing(false /*shuttingDown*/); 515 } else { 516 PowerState currentState = mHal.getCurrentPowerState(); 517 if (currentState != null && needPowerStateChange(currentState)) { 518 onApPowerStateChange(currentState); 519 } else { // power controller woke-up but no power state change. Just shutdown. 520 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" + 521 currentState); 522 doHandleShutdown(); 523 } 524 } 525 } 526 527 private void doHandleNotifyPowerOn() { 528 boolean displayOn = false; 529 synchronized (this) { 530 if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) { 531 displayOn = true; 532 } 533 } 534 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 535 // wrapper will not send it forward if it is already called. 536 wrapper.callOnPowerOn(displayOn); 537 } 538 } 539 540 private boolean needPowerStateChange(PowerState newState) { 541 synchronized (this) { 542 if (mCurrentState != null && mCurrentState.equals(newState)) { 543 return false; 544 } 545 return true; 546 } 547 } 548 549 private void doHandleShutdown() { 550 // now shutdown 551 for (PowerServiceEventListener listener : mListeners) { 552 listener.onShutdown(); 553 } 554 int wakeupTimeSec = 0; 555 if (mHal.isTimedWakeupAllowed()) { 556 wakeupTimeSec = getWakeupTime(); 557 } 558 mHal.sendShutdownStart(wakeupTimeSec); 559 mSystemInterface.shutdown(); 560 } 561 562 private int getWakeupTime() { 563 int wakeupTimeSec = 0; 564 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 565 int t = wrapper.handler.getWakeupTime(); 566 if (t > wakeupTimeSec) { 567 wakeupTimeSec = t; 568 } 569 } 570 return wakeupTimeSec; 571 } 572 573 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) { 574 synchronized (this) { 575 releaseTimerLocked(); 576 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) { 577 // entered sleep after processing start. So this could be duplicate request. 578 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore"); 579 return; 580 } 581 } 582 if (shutdownWhenCompleted) { 583 doHandleShutdown(); 584 } else { 585 doHandleDeepSleep(); 586 } 587 } 588 589 private synchronized void setCurrentState(PowerState state) { 590 mCurrentState = state; 591 } 592 593 @Override 594 public void onDisplayBrightnessChange(int brightness) { 595 PowerHandler handler; 596 synchronized (this) { 597 handler = mHandler; 598 } 599 handler.handleDisplayBrightnessChange(brightness); 600 } 601 602 private void doHandleDisplayBrightnessChange(int brightness) { 603 mSystemInterface.setDisplayBrightness(brightness); 604 } 605 606 private void doHandleMainDisplayStateChange(boolean on) { 607 Log.w(CarLog.TAG_POWER, "Unimplemented: doHandleMainDisplayStateChange() - on = " + on); 608 } 609 610 public void handleMainDisplayChanged(boolean on) { 611 PowerHandler handler; 612 synchronized (this) { 613 handler = mHandler; 614 } 615 handler.handleMainDisplayStateChange(on); 616 } 617 618 /** 619 * Send display brightness to VHAL. 620 * @param brightness value 0-100% 621 */ 622 public void sendDisplayBrightness(int brightness) { 623 mHal.sendDisplayBrightness(brightness); 624 } 625 626 public synchronized Handler getHandler() { 627 return mHandler; 628 } 629 630 // Binder interface for CarPowerManager 631 @Override 632 public void registerListener(ICarPowerStateListener listener) { 633 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 634 mPowerManagerListeners.register(listener); 635 } 636 637 @Override 638 public void unregisterListener(ICarPowerStateListener listener) { 639 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 640 doUnregisterListener(listener); 641 } 642 643 private void doUnregisterListener(ICarPowerStateListener listener) { 644 boolean found = mPowerManagerListeners.unregister(listener); 645 646 if (found) { 647 // Remove outstanding token if there is one 648 IBinder binder = listener.asBinder(); 649 synchronized (mPowerManagerListenerTokens) { 650 if (mPowerManagerListenerTokens.containsKey(binder)) { 651 int token = mPowerManagerListenerTokens.get(binder); 652 finishedLocked(binder, token); 653 } 654 } 655 } 656 } 657 658 @Override 659 public void requestShutdownOnNextSuspend() { 660 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 661 mShutdownOnNextSuspend = true; 662 } 663 664 @Override 665 public int getBootReason() { 666 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 667 // Return the most recent bootReason value 668 return mBootReason; 669 } 670 671 @Override 672 public void finished(ICarPowerStateListener listener, int token) { 673 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER); 674 synchronized (mPowerManagerListenerTokens) { 675 finishedLocked(listener.asBinder(), token); 676 } 677 } 678 679 private void finishedLocked(IBinder binder, int token) { 680 int currentToken = mPowerManagerListenerTokens.get(binder); 681 if (currentToken == token) { 682 mPowerManagerListenerTokens.remove(binder); 683 if (mPowerManagerListenerTokens.isEmpty() && 684 (mCurrentState.mState == PowerHalService.STATE_SHUTDOWN_PREPARE)) { 685 // All apps are ready to shutdown/suspend. 686 Log.i(CarLog.TAG_POWER, "Apps are finished, call notifyPowerEventProcessingCompletion"); 687 notifyPowerEventProcessingCompletion(null); 688 } 689 } 690 } 691 692 private class PowerHandler extends Handler { 693 694 private final int MSG_POWER_STATE_CHANGE = 0; 695 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1; 696 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2; 697 private final int MSG_PROCESSING_COMPLETE = 3; 698 private final int MSG_NOTIFY_POWER_ON = 4; 699 700 // Do not handle this immediately but with some delay as there can be a race between 701 // display off due to rear view camera and delivery to here. 702 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500; 703 704 private PowerHandler(Looper looper) { 705 super(looper); 706 } 707 708 private void handlePowerStateChange() { 709 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE); 710 sendMessage(msg); 711 } 712 713 private void handleDisplayBrightnessChange(int brightness) { 714 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0); 715 sendMessage(msg); 716 } 717 718 private void handleMainDisplayStateChange(boolean on) { 719 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 720 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on)); 721 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS); 722 } 723 724 private void handleProcessingComplete(boolean shutdownWhenCompleted) { 725 removeMessages(MSG_PROCESSING_COMPLETE); 726 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0); 727 sendMessage(msg); 728 } 729 730 private void handlePowerOn() { 731 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON); 732 sendMessage(msg); 733 } 734 735 private void cancelProcessingComplete() { 736 removeMessages(MSG_PROCESSING_COMPLETE); 737 } 738 739 private void cancelAll() { 740 removeMessages(MSG_POWER_STATE_CHANGE); 741 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE); 742 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 743 removeMessages(MSG_PROCESSING_COMPLETE); 744 removeMessages(MSG_NOTIFY_POWER_ON); 745 } 746 747 @Override 748 public void handleMessage(Message msg) { 749 switch (msg.what) { 750 case MSG_POWER_STATE_CHANGE: 751 doHandlePowerStateChange(); 752 break; 753 case MSG_DISPLAY_BRIGHTNESS_CHANGE: 754 doHandleDisplayBrightnessChange(msg.arg1); 755 break; 756 case MSG_MAIN_DISPLAY_STATE_CHANGE: 757 doHandleMainDisplayStateChange((Boolean) msg.obj); 758 break; 759 case MSG_PROCESSING_COMPLETE: 760 doHandleProcessingComplete(msg.arg1 == 1); 761 break; 762 case MSG_NOTIFY_POWER_ON: 763 doHandleNotifyPowerOn(); 764 break; 765 } 766 } 767 } 768 769 private class ShutdownProcessingTimerTask extends TimerTask { 770 private final boolean mShutdownWhenCompleted; 771 private final int mExpirationCount; 772 private int mCurrentCount; 773 774 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) { 775 mShutdownWhenCompleted = shutdownWhenCompleted; 776 mExpirationCount = expirationCount; 777 mCurrentCount = 0; 778 } 779 780 @Override 781 public void run() { 782 mCurrentCount++; 783 if (mCurrentCount > mExpirationCount) { 784 PowerHandler handler; 785 synchronized (CarPowerManagementService.this) { 786 releaseTimerLocked(); 787 handler = mHandler; 788 } 789 handler.handleProcessingComplete(mShutdownWhenCompleted); 790 } else { 791 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS); 792 } 793 } 794 } 795 796 private static class PowerEventProcessingHandlerWrapper { 797 public final PowerEventProcessingHandler handler; 798 private long mProcessingTime = 0; 799 private boolean mProcessingDone = true; 800 private boolean mPowerOnSent = false; 801 private int mLastDisplayState = -1; 802 803 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) { 804 this.handler = handler; 805 } 806 807 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) { 808 mProcessingTime = processingTime; 809 mProcessingDone = false; 810 } 811 812 public synchronized long getProcessingTime() { 813 return mProcessingTime; 814 } 815 816 public synchronized void markProcessingDone() { 817 mProcessingDone = true; 818 } 819 820 public synchronized boolean isProcessingDone() { 821 return mProcessingDone; 822 } 823 824 public void callOnPowerOn(boolean displayOn) { 825 int newDisplayState = displayOn ? 1 : 0; 826 boolean shouldCall = false; 827 synchronized (this) { 828 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) { 829 shouldCall = true; 830 mPowerOnSent = true; 831 mLastDisplayState = newDisplayState; 832 } 833 } 834 if (shouldCall) { 835 handler.onPowerOn(displayOn); 836 } 837 } 838 839 @Override 840 public String toString() { 841 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime=" 842 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]"; 843 } 844 } 845 } 846