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