Home | History | Annotate | Download | only in car
      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