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.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